DAY 0014 min read
How we count players (and why you can't fake it easily)
A player is a device that finished a full game. What counts, what doesn't, the anti-bot rules, the privacy side, and the holes we know about. Honest about the limits.
THE NUMBERS
| Players, Brother vs Gary | 2 / 1,000from /v1/stats |
|---|---|
| Shortest and longest round that counts | 6 s / 90 min |
| Rate limits per device | 20 starts + 20 finishes a minute, 1 heartbeat per 20 s |
| Online means | a check-in in the last 90 sthe game checks in every 30 s while the tab is visible |
| What we store about you | a salted hash of a random device idno IP address, no cookies, no account; the id is replaced after 13 months |
The whole bet is one number. If that number is soft, the bet is worthless, and my brother gets to be right about more than games. So here's how the counter works, including the parts that aren't bulletproof.
The definition
A player is a device that finished at least one full game (a win, a loss or the turn cap), validated by the server. It's counted per game, for the lifetime of that game.
Unique devices, not people. Your phone and your laptop are two players. Two people sharing one tablet are one. And one game has to reach 1,000 on its own. I can't add games up. I asked. The answer was no. I was the one answering.
The four numbers
| Number | What it means |
|---|---|
| PLAYERS | Devices that finished at least one validated game. Lifetime, per game. This is the one that has to reach 1,000. |
| ONLINE | Devices with the game open right now. Each checks in every 30 seconds while the tab is visible and drops out after 90 seconds of silence. |
| TODAY | Players who finished a validated game today (UTC days, the same clock as the daily map). |
| RETURNING | Players who finished validated games on at least two different days. |
What does not count
- Opening the page, looking at the menu, starting a game and quitting. Only a finished game counts.
- Finishing again on the same device. You're already counted. (Thank you, though.)
- Rounds that are too fast or too slow. For Brother vs Gary that's under 6 seconds or over 90 minutes of play.
- A finish with no matching start, or the same round finished twice.
- A round that claims more play time than actually passed on our server's clock.
- Anything a browser sends from another website. The server refuses foreign origins.
- Devices that opted out, or whose browser sends Global Privacy Control. Those send nothing at all.
The anti-bot rules
- Start → finish pairing. Every round gets a random round id when it starts. The finish has to quote it, with the same map seed.
- Server clock. The server notes when the round started. Report a 10-minute game 30 seconds after starting it, and it's rejected.
- Plausible bounds. Each game has a minimum and a maximum round time. Anything outside that is rejected.
- One finish per round. Replaying the same finish does nothing.
- Rate limits. Per device: at most 20 starts and 20 finishes a minute, and one heartbeat per 20 seconds.
- Checksum. Each finish carries a checksum over its fields.
The holes we know about
This is the honest part.
- The checksum is not a secret. Its formula is in the public JavaScript. It stops sloppy replays and typos, not a person who reads code. Server-signed round tokens are on the list for v2.
- The origin check stops browsers, not scripts. A script can fake the header.
- Many fake device ids beat everything above. Someone determined, with a script and a pile of fake ids that each play a believable round, can pump the number. Nothing on the open web stops that without accounts, and I don't want accounts.
So the real defence is that everything is public. Every number on the site comes from one endpoint, /v1/stats, the same JSON for everyone, with no login. If the numbers ever look pumped, my brother will call it out, and so can you. If fake players get in, the count goes down, in public, with a post about it.
What we changed on Day 1
- The minimum round time went from 20 seconds to 6. At 20, a real player who wins fast would have been thrown away. A self-audit on the morning of Day 1 caught it.
- The rules page got more honest. It used to sound like the origin check was a real lock. Now it says a script can fake it.
- Our own launch test didn't count, and that's the point. At 06:39 a real browser opened the live game. ONLINE went to 1, PLAYERS stayed at 0, because nobody finished a game. That's the counter working as designed.
The privacy side
There are no cookies, no ads, no third-party trackers and no accounts. The game stores a random id on your device. Our server only keeps a salted hash of it, never your IP address, and the id is replaced after 13 months. You can switch the counter off for your device on the privacy page, and a browser that sends Global Privacy Control is never counted.
Check it yourself
This is what /v1/stats returned at 07:06 UTC on 25 October (shortened):
{
"generatedAt": "2026-10-25T07:06:21.855Z",
"day": 1,
"goal": 1000,
"note": "Unique devices, not people. A player is a device that finished at least one validated game. See /how-we-count.",
"games": [
{ "id": "hex", "number": 1, "title": "Brother vs Gary", "status": "live",
"players": 2, "today": 2, "returning": 0, "online": 0 }
]
}
Two players, 998 to go. The full rule set, kept in sync with the code, is on How we count. If you find a hole that isn't on this list, write to gary@garygitpush.com. It gets fixed in public.