Every public page can hand out images of its own numbers. Paste one into a README, a landing page, or a tweet and it keeps itself current — the image is regenerated from your live widget data, so there is nothing to re-paste when a number changes.
All embed endpoints are public and unauthenticated. They only ever serve data your page already shows publicly: a private or hidden widget has no badge, and a widget set to disclose growth only never emits its absolute value in any format.
Find every snippet on this page in the app: open your page, click Embed, and pick a tab. The previews there reflect the exact options you choose.
The five embeds
| Embed | Endpoint | Best for |
|---|---|---|
| Social card | /og/{slug}.png |
Link previews on X, LinkedIn, Slack, Discord |
| Website badge | /badge/{slug}.svg |
A live-stats strip in your site footer |
| README badge | /badge/{slug}/{widget_id}.svg |
A row of metric badges under a README title |
| Chart | /embed/chart/{slug}/{widget_id}.svg |
Showing a trend, not just a number |
| Featured badge | /featured/dark.svg |
A "Featured on infra.page" promo pill |
Shared options
theme, color, and label work the same way on every embed that renders a metric. They are named after the shields.io parameters of the same name, so the vocabulary should already be familiar.
| Parameter | Values | Default |
|---|---|---|
theme |
dark, light |
dark |
color |
Hex (3fbf8f, #3fbf8f, abc) or a name: brightgreen, green, yellow, orange, red, blue, purple, pink, teal, cyan, lime, grey, black |
Your page's accent color |
label |
Any short text, replacing the widget's own label | The widget's label |
An unrecognised value is ignored rather than treated as an error — a typo in a README renders the default badge instead of a broken image.
Drop the # when passing a hex color in a URL. # starts the fragment, so ?color=#3fbf8f sends nothing to the server. ?color=3fbf8f works.
README badges
One badge per widget, sized and shaped like the build badges already in your README.
Wrap it in a link back to your page so the badge sends traffic, not just information:
[](https://infra.page/p/my-project)Styles
style selects the badge shape:
| Value | Result |
|---|---|
flat |
The classic 20px pill with a subtle sheen (default) |
flat-square |
Same pill, square corners, matte |
for-the-badge |
Taller, upper-cased, letter-spaced |
card |
A 220×90 branded tile with the number as the hero |
Use card where a 20px pill would disappear — a landing page hero, or next to a Product Hunt badge. Use flat in a README row, where matching the surrounding badges matters more than standing out.
The README badges tab lists every badge-able widget at once and has a Copy all as Markdown button that emits the whole row. That is almost always what you want when setting up a README for the first time.
Charts
A chart embed draws one widget's recorded history rather than its current value.
| Parameter | Values | Default |
|---|---|---|
period |
7d, 30d, 90d, 12m |
7d |
metric |
A series key the widget publishes, e.g. stars, mrr_cents, visitors |
The widget's first series |
Charts are built from the daily snapshots infrapage records for every widget, so a chart can only reach as far back as your page has been running.
Free pages render the last 7 days whatever period asks for. Pro unlocks the full window. Self-hosted installs are never clamped.
Three formats
The .svg form is the one that matters, because GitHub strips <iframe> from README markdown — an iframe-only chart can never appear where developers read.
[](https://infra.page/p/my-project)Use .html in an <iframe> on your own site, where it reflows to the container:
<iframe
src="https://infra.page/embed/chart/my-project/wgt_abc123.html?period=12m"
title="Live metrics"
width="640" height="320"
style="width:100%;max-width:640px;border:0;border-radius:12px;overflow:hidden"
loading="lazy"></iframe>.png renders at 2× for the surfaces that refuse SVG — mainly social crawlers.
What can be charted
A widget needs recorded numeric history and a fully-disclosed public metric. Widgets set to show growth only cannot be charted at all: a chart is a sequence of absolute values, so there is no honest way to draw one without publishing the numbers you chose to withhold. Those widgets return the not-found card rather than a degraded chart.
Social card
The 1200×630 image shown when someone shares your page. It carries the metrics you picked in the Featured metrics list, up to three.
[](https://infra.page/p/my-project)Set width="1200" height="630" when embedding as HTML — without them the card reflows the host page as it loads.
/og/w/{slug}/{widget_id}.png produces the same card for a single widget's number.
Website badge
A 28px strip for a site footer: a liveness pip, your featured metrics, and the infra.page mark.
<a href="https://infra.page/p/my-project" rel="nofollow">
<img src="https://infra.page/badge/my-project.svg?theme=light" alt="My Project — live stats" height="28">
</a>The mark is removed on Pro with de-branding enabled.
Caching and freshness
| Embed | Cache |
|---|---|
| Badges, charts | 5 minutes |
| Social cards | 10 minutes |
| Featured badge | 24 hours (it carries no live data) |
Every embed shows a live or idle marker earned from when your page last fetched fresh upstream data — not a decoration. A page that has gone quiet reads idle rather than claiming a freshness it can't prove.
Where your embeds are showing up
Open Embed on any page you own and the top of the modal reports how many third-party sites rendered your embeds in the last 30 days, and which ones.
This is owner-facing only. It never feeds the /discover ranking, and there is no public "embedded on N sites" counter — that number mostly measures the traffic of whoever embedded you, which is a poor proxy for whether a project is worth looking at. Loads referred from infra.page itself (your own page, the editor previews) are not counted.