A chart in your GitHub README that updates from CI
buildstats renders an SVG line chart of any number your CI pushes, per commit, at a URL you put in the README. Light and dark, 30 to 1,000 points, 400 to 1,200 px wide. Free for public repos; private $9/month.
GitHub renders images in READMEs and nothing else: no scripts, no iframes, no live widgets. The usual way to get a chart there is a workflow that draws a PNG and commits it, which puts a bot commit on every run. buildstats serves the chart instead, so the README references one URL and the image changes when the data does.
The embed
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://buildstats.io/acme/app/bundle_gzip.svg?theme=dark">
<img alt="bundle_gzip on main, last 200 commits" src="https://buildstats.io/acme/app/bundle_gzip.svg">
</picture>
The picture element is what makes GitHub swap the image with the viewer's theme; plain Markdown  works too, with the light chart for everyone. GitHub fetches the image through its camo proxy and caches it; public charts carry a 5-minute cache, so a push shows up in the README within minutes.
What the chart shows
One line per metric, or one line per variant when a metric has variants like bundle/main and bundle/vendor, up to 8 on one chart. The x axis is commit order on the branch, the y axis is the value with its unit, and the latest value, the unit and the number of commits are printed on the chart so a screenshot still reads. Values with a bytes unit are shown as kB and MB.
URL parameters
| Parameter | Values | Default | Effect |
|---|---|---|---|
| n | 30, 50, 100, 200, 500, 1000 | 200 | How many of the latest points to draw |
| w | 400, 600, 800, 1000, 1200 | 800 | Width in pixels; the height follows at a 3.1:1 ratio, so 800 by 258 |
| theme | light, dark | light | Colour scheme |
| ref | A branch name, like release | The default branch | Which branch's history to draw |
| t | Image token | None | Required for private projects |
Defaults are left out of canonical URLs, so /bundle_gzip.svg and /bundle_gzip.svg?n=200&w=800 are the same image. Pull request branches have their own history too; ?ref=refs/pull/42/merge draws it while the pull request's data is kept, which is 90 days after its last push.
Badges next to the chart

/badge.svg is a 20-pixel shields-style badge with the latest value; /badge.json is the shields.io endpoint format for custom colours and logos. The badges page covers both.
Where the numbers come from
- uses: bitgate/buildstats@v1
with:
metrics: |
bundle_gzip=$(gzip -9c dist/app.js | wc -c) bytes lower
tests=$(jq '.numPassedTests' report.json) higher
The Action pushes up to 50 metrics per step and signs in with the workflow's OIDC token, so a public repository needs no account and no secret. Outside GitHub Actions, a project API key and one curl call do the same. Each metric keeps 50,000 points per branch, and a project holds 100 metrics.
Limits and pricing
| Public repositories | Private repositories | |
|---|---|---|
| Price | Free | $9/month per GitHub user or organization |
| Chart URL | Public | Unguessable token URL |
| Image cache | 5 minutes | 1 minute |
| Metrics per project | 100 | 100 |
| Points per metric and branch | 50,000 | 50,000 |
| Points per chart | 30 to 1,000 | 30 to 1,000 |
| Widths | 400 to 1,200 pixels | 400 to 1,200 pixels |
| Variants per chart | 8 | 8 |
Everything else is on the pricing page.
Other ways to get a chart into a README
A workflow can render a PNG with matplotlib or vega and commit it, which works for any chart style at the cost of a commit per run and a repository that grows with images. github-action-benchmark draws its charts on a GitHub Pages site, not in the README. Grafana and Datadog charts need a public snapshot and a screenshot. Image services like QuickChart render a chart from a URL, but the data has to be in the URL. buildstats keeps the data and renders the SVG, so the README holds one line and nothing is committed.
Questions
Does the chart work in a private repository?
Yes. Private projects get image URLs with an unguessable token that members can rotate. Anyone with the URL can view the image; the project pages themselves require membership.
Can I show two metrics on one chart?
Variants of one metric share a chart: bundle/main and bundle/vendor draw as two lines on /bundle.svg. Separate metrics each have their own chart; put two picture elements side by side in a table.
Why does the README show an old value?
GitHub caches images through its proxy and buildstats sets a 5-minute cache on public charts. Wait a few minutes; nothing needs a commit.
Is it an SVG or a PNG?
An SVG, rendered on the server, so it is sharp at any size and under the 4 MB that readers and crawlers accept.
Can I use the chart outside GitHub?
Yes. The URL works in any HTML page, a wiki, a Notion page or a status page. The same light and dark variants apply.