How the Global Leaderboard Works (and Why It's Harder Than It Looks)

By Roberto Cantore · Published on March 22, 2026 · 8 min read

A global leaderboard sounds straightforward. Store a score, sort by value, display the list. In practice, a competitive leaderboard for a browser game has a dozen non-obvious problems to solve, and most of them only reveal themselves once real players start trying to break things. Here's how Mirlo Volador's leaderboard is actually built, and the decisions behind it.

Why Supabase

The leaderboard needed a real-time database with a public API, fine-grained access control, and the ability to handle concurrent writes from players around the world. I chose Supabase for this, and I'd make the same choice again.

Supabase is essentially PostgreSQL with a REST and real-time layer on top. For a project like this — a side project, not a funded product — the managed infrastructure is important. I'm not running servers. I'm not managing connection pools. When a player in Japan submits a score at the same time as a player in Brazil, Supabase handles the concurrent writes without me thinking about it.

The row-level security policies in Supabase were also a key factor. They let me enforce rules at the database level: a player can only update their own profile, a player can only submit scores tied to their own session, the public leaderboard view is read-only for everyone. These rules exist in the database itself, not just in the application code. That matters when you're building something that the whole internet can poke at.

The Account Model: Username Only

I made a deliberate decision early on: no email addresses, no passwords, no real names. Players pick a username and that's it. This decision had two motivations.

First, I genuinely believe you shouldn't collect data you don't need. For a leaderboard, I need a display name and a score. I don't need to know who you are outside of the game. The signup form reflects that. The less data I hold, the less I have to protect, and the less damage a hypothetical breach could do.

Second, friction kills signups. Every field you add to a registration form reduces the percentage of people who complete it. The simpler the profile creation, the more players actually join the leaderboard. And a leaderboard with more players is more interesting for everyone.

The trade-off is account recovery. If you forget your pilot name or clear your browser storage, your profile is gone. There's no email address to send a reset link to. I decided this was an acceptable trade-off for a casual browser game. This is not your bank account.

The Anti-Cheat Problem

Here's the uncomfortable truth about any browser game with a leaderboard: you can't fully trust the client. The game runs in JavaScript. Anyone with a browser console can, in principle, call the score submission function with whatever number they want. This is a real problem.

My approach is layered. It doesn't make cheating impossible — nothing does in a browser game — but it makes it annoying enough that casual cheaters don't bother.

The first layer is session tokens. When a game starts, the server issues a signed session token with a timestamp. When a score is submitted, it must include that token. A token is single-use and expires after a time window that corresponds to the maximum plausible game length. You can't reuse a token or backdate it.

The second layer is plausibility checking. The server validates that the submitted score is achievable in the time window encoded in the session token. A score of 500 submitted from a session that started 30 seconds ago is impossible at the game's pipe speed, so it's rejected. The pipe gap size, pipe speed, and game timing are all server-side constants that feed into this check.

The third layer is rate limiting. The score submission endpoint has per-profile rate limits. If a profile submits more than a certain number of scores per hour, the excess submissions are silently dropped. This catches bots that try to farm a high score through brute force.

Cloudflare Turnstile sits in front of profile creation and score submission as a bot protection layer. It's a much better experience than a CAPTCHA — players usually don't even notice it — but it stops automated scripts from creating thousands of fake profiles.

Does any of this stop a determined cheater who wants to spend an afternoon reverse-engineering the token format? No. But the leaderboard is for fun, not prize money. The goal is to keep the top of the board looking legitimate to normal players, not to build a cryptographically secure scoring system.

Country Detection

One of the details players notice is the country flag next to their name on the leaderboard. This is cosmetic but adds a lot to the feel of competing globally. The implementation is straightforward: when a player creates a profile, the client calls ipapi.co with no arguments (it uses the request's IP address by default) and gets back a two-letter country code. That code is stored with the profile.

There are a few gotchas here. First, VPN users will get the flag of their VPN exit node's country, not their real country. That's fine. It's not a verified identity system. Second, ipapi.co has a free tier with a request limit. I cache the country code in the profile immediately so subsequent logins don't hit the API again. Third, the country is stored only as a two-letter code. The actual IP address is never written to the database.

Players occasionally ask how to change their flag. The honest answer is: delete your profile and create a new one. The country is detected once at profile creation and never updated, which avoids the complexity of re-detection and the edge case of someone creating a profile while traveling.

Real-Time vs. Polling

Supabase supports real-time subscriptions over WebSockets. In theory, this means the leaderboard can update live as scores come in — no refresh needed. In practice, I use a hybrid approach.

The main leaderboard view polls every 30 seconds rather than maintaining a persistent WebSocket connection. This is a deliberate choice. A persistent WebSocket connection per player doesn't scale well when you have many concurrent players, and for a leaderboard that updates a few times per minute, 30-second polling is indistinguishable from real-time to a human. The WebSocket subscription is reserved for the brief window right after a player submits their own score, when they want to see their placement update immediately.

Profile Deletion

Players can delete their profile at any time from the in-game interface. When they do, the deletion is immediate and permanent: the profile row is deleted, all associated score rows are deleted via cascade, and the entry disappears from the leaderboard. There is no soft delete, no 30-day grace period. When it's gone, it's gone.

This was the right call from a privacy standpoint, but it created one annoying edge case: a player who accidentally deletes their profile has no recourse. I've had a few messages about this. My answer is always the same: I can't restore it, and I wouldn't even if I could, because the deletion is supposed to be permanent and I don't hold a backup of individual profiles. The solution is to not delete your profile unless you mean it.

What the Data Actually Shows

A few observations from watching the leaderboard evolve since launch:

The top scores cluster heavily around round numbers. Players seem to aim for milestones — 50, 100, 200 — and once they reach one, they stop playing for a while. This is a well-known pattern in casual games but it's striking to see it in the data so clearly.

Country representation is more diverse than I expected. The leaderboard regularly has players from 30 or more countries in the top 100. Argentina (my home country) is well represented, which is nice to see, but the top of the board at any given time is usually dominated by players from Europe and Southeast Asia.

Profile deletion spikes happen after score resets or after periods of heavy play. Players seem to delete and recreate profiles to start fresh rather than living with a score they're not happy with. I'm not sure what to do about this, if anything.

Building this leaderboard was genuinely one of the more interesting engineering problems in the project. The game itself is a finite state machine. The leaderboard is a distributed system with untrusted clients and adversarial users. Different problems, different mindsets. Both worth building.

Related Articles