← Back to the app

What we store

Last updated 28 August 2026

This is a scoreboard for people who play mahjong together. It is not a product with a funnel, and it does not make money from anybody's data. This page says exactly what is kept, why, and how to get rid of it.

The short version

No email address. No analytics. No advertising. No third-party trackers. One cookie, and it only says you are signed in. You can delete your account from Settings, and it takes your rooms with it.

What an account is

A username, and a way to prove it is yours. There is no email field anywhere in the database, which has one real consequence worth saying out loud: nobody can reset a forgotten password for you. If it is lost, the account is lost.

If you sign in with a password, the password itself is never stored. What is kept is a PBKDF2-SHA256 hash with 100,000 iterations and a random per-account salt, which cannot be turned back into the password. Use a password you do not use elsewhere anyway.

Signing in with Google

Optional, and it changes almost nothing about what is stored here. We ask Google for one thing: openid, the scope that answers "is this the same person as last time". Not your email, not your name, not your photo, not your contacts. Google is not told anything about you in return; it learns only that you signed in to this app, which it would learn anyway.

What is kept is the stable identifier Google uses for you, an opaque number next to your account here. That is the whole record. Because we never ask for your email address, there is still no email column for one to go in, and the paragraph above stays true.

Connecting Google to an account you already have is done from Settings, and is the right way round: signing in with Google first would make a second, empty account, and the rooms you are in would still belong to the first one. Disconnecting is not offered, because for an account created through Google it is the only way in and removing it would lock you out of your own rooms.

What playing creates

  • Rooms: a name, and who is in them.
  • Players: the names on a room's roster. Most are guests: a name and nothing more, belonging to somebody who has no account and never will. A player can optionally be linked to an account, which is how a roster says which name is yours.
  • Games and hands: every hand recorded, as an event with a timestamp. These are the score: the totals are recalculated from them rather than stored, which is why an undo is exact and why a correction fixes history rather than patching over it.
  • Invite codes: six characters, who made them, and when they expire.

Your profile picture

Optional, and there is a drawn face for everybody who does not set one. If you do, the picture never leaves your device as the file you chose: the app crops it to a square, shrinks it to 512 pixels and re-encodes it as WebP first, which is also what removes the time and the place the photograph was taken. Only that copy is uploaded, to a private R2 bucket.

It is not public and has no shared link. It is shown to you, to the people you are friends with, and to the people you share a room with, and to nobody else. Change it or remove it at any time from your profile, and removing it deletes the stored image rather than hiding it.

Pilot hand photographs

A private scanner pilot lets a super moderator attach a photograph of a winning hand after consent is explicitly confirmed. The frame should contain the tiles, not people's faces. The app accepts only a cropped WebP copy, limited to 5 MB, and refuses EXIF, location and other embedded metadata.

A super moderator can also record which tiles are in the photograph and what the hand was counted for, so the picture has something to be read against. That is a list of tile names and scoring reasons, and nothing about the people at the table.

The photograph is not public and has no shared link. Only a super moderator can upload, view, approve or delete it. Unapproved photographs are deleted after 90 days. A photograph explicitly approved for scanner training is kept until it is manually deleted, unless the account that uploaded it is deleted. Ask the person running this instance to have one removed.

Who can see it

A room is visible to the people in it, and to nobody else. Joining takes a code that somebody in the room reads out. Within a room, everyone sees the roster, the games, the leaderboard and each other's profile pictures; one person (the master) is the one who records hands.

Nothing is public. There are no shared links, no search, and no way to browse rooms you are not in.

Cookies

One, called sid. It holds a random session token, not your name and not your password, and it is set HttpOnly, Secure and SameSite=Lax, so scripts cannot read it and other sites cannot send it. It lasts 30 days, and signing out deletes it on both ends.

There are no analytics or advertising cookies, because there are no analytics or advertising.

What stays on your device

The game in progress is saved in your browser's local storage, along with a cache of the rooms and lists you have looked at. That is what lets the app keep working at a table with no signal. That is the point of the design, not an optimisation. None of it leaves your device except as the hands you record, and deleting your account clears all of it.

Failed sign-ins

A failed sign-in records the username tried and the IP address it came from, so repeated guessing can be slowed down. Rows older than the counting window are deleted automatically, and signing in successfully clears yours. Account creation is counted the same way, per address, to stop a script minting accounts.

When something breaks

If the app throws an error in your browser, it sends a report so it can be fixed. That report is the error message, the stack trace, which page you were on, and your browser's user-agent string, plus your username if you are signed in, so a report can be matched to a "it did something odd on Friday". It does not include room names, player names, scores, or anything you typed.

Reports go into the server log and nothing else. There is no third-party error service, and nothing is sold or shared. The same fault is reported once per visit, so a bug that repeats does not repeat the report.

Where it lives

On Cloudflare: Workers for the application, D1 for the database, and two private R2 buckets, one for profile pictures and one for pilot hand photographs. Cloudflare processes it on our behalf and stores it in their network; they do not use it for anything of their own. Traffic is encrypted in transit.

How long it is kept

Rooms and their games are kept until somebody deletes them, because a leaderboard that quietly forgot last winter would be worse than useless. Sessions expire after 30 days. Invite codes expire after seven, or when the master replaces them. A profile picture is kept until you replace it or remove it. Unapproved pilot photographs expire after 90 days; approved training photographs remain until they are manually deleted.

Deleting your account

Settings → Account → Delete my account. It asks you to type your username, because it cannot be undone. What happens:

  • Your account, every session, your sign-in records, and any connected Google identity go.
  • Any room only you are in is deleted with its games.
  • Rooms you share stay, and so do their games. That is other people's history too. Your name comes off the seats you had claimed; the player names themselves remain, because somebody did sit there and play those hands.
  • Your profile picture is deleted.
  • Pilot photographs uploaded by your account are deleted, including ones approved for training. Approval records on photographs uploaded by somebody else are anonymised.
  • If you keep the score in a shared room, you will be asked to hand that over first. A room with no master is a room nobody can score in again.

Getting a copy of your data

There is no download button. Everything about you is already on screen in the app (your rooms, your games, every hand) and this is a small app run by people you know, so: ask, and it will be exported by hand.

Changes

If what is stored changes, this page changes with it and the date at the top moves. Keeping anything genuinely new will be asked for rather than assumed.

Asking about any of this

Message whoever invited you to the room, or the person who runs this instance. It is a small app run by people you know.

← Back to the app