#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 withsubmit(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.