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

  1. Mint a token server-side with your API key.
  2. 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.

Managed embed html
<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.

Mint bash
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" } }
FieldRequiredNotes
typeYesleaderboard or badges.
keyFor leaderboardThe leaderboard's key.
participantFor badgesThe participant's external_id.
themeNodark 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 embed html
<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-widgetleaderboard or badges (default leaderboard).
  • data-flyhalf-themedark or light.
  • 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.

Direct iframe html
<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.