GitHub Star History API Tutorial: Build a Growth Chart

GitHub released a repository-growth endpoint on September 4, 2026, with an unusual bargain: less personal data, better analytics. This GitHub star history API tutorial shows how to fetch that data, turn the weekly buckets into chart-ready rows, and avoid the quiet mistakes that make a tidy dashboard lie politely.

The request itself is one line. The useful work starts afterward, because the response runs backward through time, stores daily counts in a Sunday-first array, and includes an unfinished current week. Get those details right and you have a clean momentum signal. Get them wrong and Tuesday may become Thursday while your trend line confidently heads in reverse.

Why GitHub replaced names with weekly counts

The new endpoint is a repair job with a privacy constraint. In its June 30 restriction announcement, GitHub said public stargazer and watcher lists were being misused to collect user data for spam. Access to the identity-level stargazer list would therefore be limited to repository admins and collaborators.

That protected users but broke a legitimate workflow. Maintainers, investors, and developer-tool vendors had been reconstructing growth curves by collecting individual star events. GitHub’s September 4 release note restores the time series without restoring the people behind it.

The trade is better than it first appears. Most growth dashboards never needed usernames; they needed counts and dates. The old payload nudged every analytics client toward becoming a small identity database. The replacement gives the legitimate use case a cleaner shape while removing the most abuse-friendly field. Turns out privacy can improve an API.

GitHub star history API tutorial: make the first request

For a public repository, start without a token. GitHub’s starring endpoint reference says the history route works unauthenticated for public resources. Replace the owner and repository names in this request:

curl -L \
  -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  "https://api.github.com/repos/openai/openai-python/stargazers/history?per_page=2"

A live check on September 6 returned 28 stars in the in-progress week and 77 in the previous, completed week. The count endpoint showed 31,594 stars in the same snapshot. Those values will change, naturally—that is rather the point of a history API.

FieldMeaningGotcha
weekUnix timestamp anchoring the calendar weekWeek boundaries are not guaranteed to align with UTC
totalStars added during that weekThe newest week may be incomplete
daysSeven daily star countsIndex 0 is Sunday, not Monday

Use the right endpoint for the question

GitHub now exposes two aggregate routes. Use /stargazers/history for stars created over time and /stargazers/count for the repository’s current total. Do not treat the sum of historical buckets as a substitute for today’s count: people can remove stars, and GitHub explicitly says the count route excludes users who have unstarred the repository.

# Current total
curl -sS -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  "https://api.github.com/repos/OWNER/REPO/stargazers/count" | jq '.count'

# Newest weekly bucket
curl -sS -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  "https://api.github.com/repos/OWNER/REPO/stargazers/history?per_page=1" \
  | jq '.[0] | {week, total, days}'

Store both responses, but do not label their difference “churn.” GitHub documents what each route returns, not whether old history buckets are recalculated after every unstar. The safe dashboard shows historical additions and the current displayed total as separate measures instead of inventing retention data between them.

For private repositories—or any recurring job—send a fine-grained personal access token, GitHub App token, or user access token with repository Metadata: read. Keep it in an environment variable rather than gluing it into a script. If you have already built reporting around the GitHub Copilot usage metrics API, the authentication pattern will feel familiar.

Also pin the API version. GitHub’s API version policy says requests without the version header still default to 2022-11-28. Explicit beats accidental, especially when a scheduled analytics job may run untouched for months.

Turn weekly buckets into chart-ready rows

The endpoint returns the newest week first, and additional pages keep moving backward toward the repository’s creation. Most charting libraries expect the opposite. The dependency-free Python script below follows GitHub’s Link header, expands each Sunday-first bucket, and sorts the final rows from oldest to newest.

import json, os, urllib.request
from datetime import datetime, timedelta, timezone

owner, repo = "openai", "openai-python"
url = f"https://api.github.com/repos/{owner}/{repo}/stargazers/history?per_page=30"
headers = {
    "Accept": "application/vnd.github+json",
    "X-GitHub-Api-Version": "2026-03-10",
}
if token := os.getenv("GITHUB_TOKEN"):
    headers["Authorization"] = f"Bearer {token}"

buckets = []
while url:
    request = urllib.request.Request(url, headers=headers)
    with urllib.request.urlopen(request) as response:
        buckets.extend(json.load(response))
        link = response.headers.get("Link", "")
    url = next((part[part.find("<") + 1:part.find(">")]
                for part in link.split(",") if 'rel="next"' in part), None)

rows = []
for bucket in buckets:
    anchor = datetime.fromtimestamp(bucket["week"], timezone.utc)
    for offset, count in enumerate(bucket["days"]):
        rows.append({
            "date": (anchor + timedelta(days=offset)).date().isoformat(),
            "stars": count,
        })

rows.sort(key=lambda row: row["date"])
print(json.dumps(rows, indent=2))

The generated dates are chart labels derived from GitHub’s weekly anchor, not timestamps for individual star events. That distinction matters because the documentation explicitly says its week and day boundaries may not align with UTC. Aggregate data has boundaries; it just does not invite you to pretend they are more precise than the source.

Do not compare a partial week with full weeks

On September 6, the current bucket showed 28 stars, all in the first daily slot. That was Sunday, the first day of a new bucket—not a catastrophic 64% weekly decline from the prior week’s 77. For week-over-week charts, either exclude the newest bucket until it closes or label it “week to date.” A dashed line is cheaper than a bad board meeting.

Weekly star-history blocks reordered into an ascending repository growth chart

Paginate and cache without burning the rate limit

This endpoint accepts at most 30 weekly buckets per page and a page number no higher than 100. That ceiling spans up to 3,000 weeks—roughly 57.5 years—so repository age is not the practical bottleneck. Request volume is.

GitHub’s published REST API rate limits allow 60 unauthenticated requests per hour, compared with 5,000 for a standard authenticated user. Fetch both history and current count for 50 repositories and the job needs 100 requests. The anonymous allowance is gone before the coffee cools.

  • Follow the response’s Link header; do not guess how many pages exist.
  • Cache completed weekly buckets and revalidate them less often than the active week.
  • Refresh the active week and current count on your chosen schedule.
  • Store the response timestamp so readers know exactly when the chart was measured.

For multi-repository reporting, add conditional requests with the response’s ETag and monitor the X-RateLimit-Remaining header. The simplest reliable architecture is a scheduled collector writing normalized rows to storage, with the front end reading those rows instead of calling GitHub on every page load.

Use stars as attention data, not adoption data

A star curve can answer useful questions: Did a release attract attention? Did a conference talk create a spike? Is interest accelerating across several months? It cannot tell you how many people installed the software, returned a week later, deployed it, or paid for it.

This is the same measurement trap behind Hugging Face popularity metrics: the easiest number to graph is rarely the whole behavior. Pair stars with package downloads, release-asset downloads, telemetry, active installations, or revenue. Stars measure attention. Adoption leaves heavier footprints.

The unresolved question is whether aggregate history will satisfy maintainers, or whether tool builders will keep trying to recreate the identity layer GitHub deliberately removed.

A good star dashboard does not know who clicked; it knows when momentum changed, and it is honest about everything that number cannot prove.

The next dated migration checkpoint is March 10, 2028, when GitHub says the older 2022-11-28 REST API version reaches end of support. Before then, the starring changelog will show whether this privacy-first contract holds as integrations move over.

Get the Daily Pulse

Sharp analysis on what's actually moving in AI. No hype, no filler, no weekly digest.

Get the Daily Pulse

Sharp AI analysis, daily. Two minutes, every morning.

Get the Daily PulseTwo minutes, every morning