#Leaderboards

A shared, per-game high-score list, available to any game via the SDK. There is no setup: the table is shared infrastructure, so you just submit and read scores.

#Use it

<script src="/sdk/v1/arcade.js"></script>
Arcade.init();                                  // slug auto-detected from /games/<slug>/

await Arcade.leaderboard.submit(1234);          // integer score, 0..1e9 → { player, score, at }
const top = await Arcade.leaderboard.top(10);   // [{ player, score, at }, ...] best-per-player
const mine = await Arcade.leaderboard.me();     // { score, at, rank } | null (signed in)
const name = Arcade.leaderboard.player();       // remembered local name | null
  • Player name: defaults to the signed-in account's name; falls back to a name remembered in localStorage (prompted once) for signed-out play. Override with submit(score, { player: "Ace" }).
  • Metadata: submit(score, { meta: { level: 7 } }) takes any object, ≤1KB serialized.
  • Limit: top(n) caps at 100; results are the best score per player, highest first.

Multiple boards: a game can declare extra named boards in game.json ("leaderboards": [{ "id": "wins", "name": "Most Wins" }]), rendered on the arcade profile. Pass { board } to select one from the browser:

await Arcade.leaderboard.top(10, { board: "points" });
await Arcade.leaderboard.me({ board: "wins" });
await Arcade.leaderboard.submit(120, { board: "points" });

Omit it for the default board. Boards can also be written from your game's backend module (via the server submitScore helper). Sightlines and Inksight both do this.

Calls reject with ArcadeOfflineError when the API is unreachable (offline or local dev without the server running). Catch it and carry on; leaderboards are never load-bearing for play.

#Being overtaken

When a submitted score passes other players, the arcade notifies the players who lost position, not the one who submitted: the submitter is looking at the leaderboard already, and the point of a notification is reaching someone who isn't.

Nothing to wire up, it happens on submit. Two limits worth knowing: at most five players are notified per submission, and repeat overtakes of the same rival on the same board replace the earlier notice rather than stacking, so trading places all afternoon produces one inbox row, not forty.

#Show the badge

Set "features": { "leaderboard": true } in your game.json to get the 🏅 badge on the landing page. It's informational only, and the SDK works regardless.

#Endpoints (if you skip the SDK)

Endpoint Body / query
POST /api/games/<slug>/scores { player ≤24, score 0..1e9, meta? ≤1KB, board? }
GET /api/games/<slug>/scores?limit=N&me=1&board=<id> { scores: [{ player, score, at }], me? }

board is an optional slug (a-z0-9-, ≤24; omit for the default board). me=1 adds { me: { score, at, rank } } for the signed-in caller.

See also: accounts · saving game data.

View docs/guides/leaderboards.md on GitHub ↗