Embed Badge
Drop a live Hatch score into any website, README, or Notion page.
Three embed formats
1. iframe (full card)
<iframe
src="https://gohatch.fun/badge/<score-id>"
width="260"
height="40"
frameborder="0"
scrolling="no"
style="border-radius: 6px;"
></iframe>
Renders the full Hatch badge — band-tinted, aggregate, ticker, preliminary flag if present. Self-updating: the iframe re-fetches on load, so a re-scored token shows the latest aggregate next time your page reloads.
CSS sandboxing: the iframe bypasses the root layout so the parent's
header/footer never leak in, and the iframe's frame-ancestors * CSP
allows cross-origin embedding.
2. SVG shield (shields.io-style)

Renders a dark-left, band-tinted-right SVG. <img>-compatible. Good for
READMEs, PRs, GitHub issues. Cached 60s browser / 300s CDN so heavy repos
don't thrash the API.
3. One-line <script> (iframe loader)
<script src="https://gohatch.fun/api/embed?id=<score-id>"></script>
Drops the iframe in-place at the location of the <script> tag. Handy
for non-markdown surfaces where pasting an iframe is awkward.
Getting the embed code
On /score/:id, the Share & embed panel has copy buttons for all
three formats. Each copy action writes the format with the current UUID
pre-filled.
Supported surfaces:
- ✅ Personal websites (HTML)
- ✅ GitHub / GitLab READMEs (Markdown with SVG)
- ✅ Notion (iframe or Markdown)
- ✅ Substack / Ghost (iframe)
- ⚠️ Twitter — iframes not supported; share the score URL instead, the OG card renders inline
- ⚠️ Medium — strips iframes; use the SVG
Why a dedicated /badge/:id route
/badge/:id returns a raw HTML response (Next route handler with a
Response, not a page) so the global layout doesn't inject header +
footer + i18n bundle into a 40-px badge. The route is also excluded from
the global CSP's frame-ancestors 'none' via a negative lookahead in
next.config.mjs.
Security considerations
- iframes —
frame-ancestors *is scoped to/badge/*only; the rest of the site refuses cross-origin framing. - SVG — rendered server-side, no user-supplied content leaks in.
- Embed script — the loader is a static string that writes an iframe; it does not eval or fetch arbitrary user input.
If you find a way to load a badge that executes attacker-controlled code, please report via bug bounty.
Example: adding a badge to your token's README
# $YOLK
The breakfast token. Unserious about price, serious about eggs.
[](https://gohatch.fun/score/a1b2c3d4)
[](https://t.me/yolktoken)
The Hatch badge + a community link. Both update without you touching the README.
API: GET /api/badge/:id
Returns an SVG shield. Response:
Content-Type: image/svg+xml
Cache-Control: public, max-age=60, s-maxage=300
Query params: none. The band is derived from the score's aggregate.
Limits
- No rate limit on badges. We cache aggressively so heavy embeds don't incur backend cost.
- Retention: as long as the score exists.
- Deletion: if a creator requests a score be removed (via
support@gohatch.fun), the badge stops rendering and returns 410.