Game jams
A global leaderboard for your jam game, in the time it takes your coffee to brew. Free, no player accounts, works in web builds on itch.io — and the board keeps running long after the jam ends.
Why bother, mid-jam?
Because during the rating period, a leaderboard is a retention machine. Raters play a jam game once, rate it, move on — unless there's a score to beat. A visible global board turns "played it" into "played it four times trying to knock #1 off", and players who replay leave better ratings and comments. It's the cheapest engagement feature you can ship in a jam.
The parts that matter for jam conditions:
- Players need no account. Anonymous login is a persistent device ID — raters land on the board on their first run, zero sign-up friction. (Nobody creates an account to rate a jam game. They don't have to.)
- Web builds work. Board reads are CORS-simple, so an itch.io-embedded HTML5 export reads leaderboards with no proxy or server of yours. See Web export.
- It's free. No card, no tier to pick mid-jam. Register a game, get an API key, go.
- Daily and weekly boards are automatic. Every game gets all-time, weekly, and daily boards with automatic archiving — a "today's best" board resets itself while you sleep.
The 3-minute path, by engine
Godot 4 — the drop-in
Install the CheddaBoards addon from the Godot Asset Store (enable the plugin; the autoload registers itself), then:
func _ready():
CheddaBoards.set_api_key("cb_my-jam-game_xxxxxxxxx")
CheddaBoards.set_game_id("my-jam-game")
CheddaBoards.leaderboard_loaded.connect(_on_leaderboard)
await CheddaBoards.wait_until_ready()
CheddaBoards.login_anonymous() # nameless — the server names new players (Player_1248) until they pick one
func _on_game_over(score: int, streak: int):
CheddaBoards.submit_score(score, streak)
func show_leaderboard():
CheddaBoards.get_leaderboard("score", 100)
func _on_leaderboard(entries: Array):
for e in entries:
print("#%d %s - %d" % [e.rank, e.nickname, e.score])That's the whole integration. Full walkthrough: Godot quick start. Starting a game from nothing at hour zero? The template is a working project with menus, sign-in, and a leaderboard scene already wired — replace the example game with yours.
Unity — one file
Copy CheddaBoards.cs from the Unity SDK repo into your project — no packages, no scene setup:
var cb = CheddaBoards.Instance;
cb.SetApiKey("cb_my-jam-game_xxxxxxxxx");
cb.SetGameId("my-jam-game");
cb.OnLoginSuccess += (nick) => canSubmit = true;
cb.LoginAnonymous(); // nameless — see the Godot note above
// at game over:
CheddaBoards.Instance.SubmitScore(score, streak);Full walkthrough (and a complete demo game to crib from): Unity quick start.
Anything else — two HTTP calls
Bevy, Love2D, PICO-8 exports, hand-rolled JS — if it can POST JSON, it can have a leaderboard. Generate a persistent player ID client-side, then:
# submit a score
curl -X POST https://api.cheddaboards.com/scores \
-H "X-API-Key: cb_my-jam-game_xxxxxxxxx" \
-H "X-Game-ID: my-jam-game" \
-H "Content-Type: application/json" \
-d '{"playerId": "dev_1730000000_1a2b3c4d", "gameId": "my-jam-game", "score": 1500, "streak": 5}'
# read the board
curl "https://api.cheddaboards.com/leaderboard?sort=score&limit=10" \
-H "X-API-Key: cb_my-jam-game_xxxxxxxxx" \
-H "X-Game-ID: my-jam-game"Generate playerId once per player (random, e.g. dev_<unixtime>_<random>), store it locally, reuse it — that's the whole identity model. Never hard-code one: every copy of your game would be the same player. Full surface: REST quick start.
Jam checklist
- [ ] Register the game before the jam starts — cheddaboards.com takes a minute, but it's a minute you won't want at hour 47. (It's infrastructure, not gameplay — the same as making your itch page ahead of time, and fine under standard jam rules. If your jam is unusually strict about pre-work, check its rules page.)
- [ ] Log in nameless (
login_anonymous()with no argument) — players keep any name they set, and new players get a generatedPlayer_1248-style name automatically - [ ] Submit only after login completes (from game-over code, not before
login_success/OnLoginSuccess) - [ ] Web export: the file must be
index.html, and test it served (python3 -m http.server), never fromfile:// - [ ] Turn
debug_loggingoff before you build - [ ] Put the leaderboard on the game-over screen, not behind a menu — raters should trip over it
- [ ] Show the current #1 score next to the player's on that screen ("Best: 48,200 — beat it?") — that line is the replay trigger
Jam-shaped details
Rate limits won't bite you. Submits are throttled at one per player per board every 2 seconds — a normal game-over loop never notices. If you're doing something weirder (per-kill submits, presence heartbeats — it's been done), targeted boards are throttled per board, so spreading writes is fine.
Rating-day traffic is nothing to plan for. A front-page itch spike needs nothing from you — no quotas to raise, no config to change, no bill at the end.
Anti-cheat is optional and probably worth skipping at first. Play sessions and time validation exist (Anti-cheat) and jam leaderboards do attract the occasional 999999999. For a 48-hour jam, ship without it and turn on score caps from the dashboard's Security tab if someone misbehaves — no code change needed for caps. Add play sessions if you keep the game alive after.
The board outlives the jam. Scores live on the Internet Computer — the leaderboard keeps working after the rating period, after the jam page goes quiet, for as long as you care. If the jam game becomes a real game, everything carries over: same API key, same board, same players.
Common jam-weekend issues
| What you see | Fix |
|---|---|
| "Not authenticated" on submit | Submit ran before login finished — submit from your game-over code |
| Blank screen on itch.io | Export must be named index.html; test it served locally, not from file:// |
| Empty leaderboard | Game ID doesn't match the dashboard |
| Score rejected | You enabled time validation but aren't starting play sessions — turn validation off, or start sessions |
| Player's name reverted | You're passing a name to login_anonymous() every launch — log in nameless |
Full list: Errors.
See also: Godot quick start · Unity quick start · REST quick start · Web export · Timed leaderboards
