Receiving results
Embeddable widgets
Two ready-made, themeable widgets — a leaderboard and a participant's badge showcase — drop into any page with a script tag. They render live data through a short-lived signed token, so nothing on the page ever holds an API key.
The two-step model
- Mint a token server-side with your API key.
- Embed it client-side. The token is the credential — read-only, live data, and it expires.
Stable embed keys (no server code)
For a leaderboard on a website, skip token minting entirely: create a managed embed in the dashboard (Leaderboards → Embeds) and copy its embed code. The key is stable until you rotate or revoke it from the same screen, and it carries the embed's styling — theme, an optional accent colour, and any custom CSS — with a live preview while you edit.
<script src="https://api.flyhalf.run/widgets/embed.js" data-flyhalf-embed="8f2a…your embed key…" data-flyhalf-widget="leaderboard"></script>
Two rules: embed keys only ever render leaderboards whose visibility is public, and they always show the anonymous top-10 — for a participant-scoped view ("me and my neighbours") or a badge showcase, use the token flow below.
Mint a token
POST /v1/widgets/tokens with an authenticated key. A leaderboard token
needs the board key; a badges token needs a participant
external id. Both accept an optional theme.
curl -X POST https://api.flyhalf.run/v1/widgets/tokens \ -H "Authorization: Bearer fh_live_…" \ -d '{ "type": "leaderboard", "key": "weekly", "theme": "dark" }' → 200 { "data": { "token": "eyJ….aB3…", "embed_url": "https://api.flyhalf.run/widgets/leaderboard?token=eyJ…", "expires_at": "2026-07-08T10:30:00+00:00" } }
| Field | Required | Notes |
|---|---|---|
type | Yes | leaderboard or badges. |
key | For leaderboard | The leaderboard's key. |
participant | For badges | The participant's external_id. |
theme | No | dark or light. |
Token lifetime
Participant-scoped tokens (a badges widget) live 15 minutes; public board tokens live 24 hours. Mint them on the fly as the page loads — they're cheap, and short TTLs keep an embed from outliving its context.
Embed with the loader script
The easiest path: drop the loader in your page and hand it the token. It injects a
responsive iframe right after itself and keeps its height synced to the content via
postMessage.
<script src="https://api.flyhalf.run/widgets/embed.js" data-flyhalf-token="eyJ…" data-flyhalf-widget="leaderboard" data-flyhalf-theme="dark" data-height="480"></script>
data-flyhalf-token— required, from the mint call.data-flyhalf-widget—leaderboardorbadges(defaultleaderboard).data-flyhalf-theme—darkorlight.data-height— initial height in px (default 480); auto-adjusts after load.
Or embed the iframe directly
Skip the loader and use the embed_url from the mint response — it's just the
iframe view with your token. The two view endpoints are
/widgets/leaderboard?token= and /widgets/badges?token= on the
API host.
<iframe src="https://api.flyhalf.run/widgets/badges?token=eyJ…" width="100%" height="480" frameborder="0"></iframe>
Widgets are live-only
A widget token is an embed credential, not API access — it can't call the API and it can't read sandbox data. Minting a badges token for a sandbox participant fails, because widgets only ever surface live data. Test the surrounding page with live participants.