Most of this is a description of how the system works rather than a promise about how it might. Where something is irreversible, it says so.
This document is available in English only. The English text is the one that governs. If it is ever translated, the translation is offered as a convenience and the English still governs.
Last updated 30 August 2026
You can play without an account, and most people do. Nothing here measures you: there is no analytics, no tracking pixel, no advertising and no third-party script watching what you read. The data we hold is the data the hunt itself needs — which code you scanned, which puzzle you answered, which token you kept.
If you sign in, that is with Google or Apple, and what other people see of you is a first name and whatever picture you chose.
Every code is a plain web page. Opening one starts a run, and a run has to belong to something, so your browser is given an identifier — a random value in a first-party cookie called rok_did, set for a year. In the phone app the same identifier is a random UUID kept in the app’s own storage and sent as an x-rok-device header.
That identifier says which run is which and nothing else. It is not a login, it is not tied to your name, and it is not checked against anything — a hostile client can invent one, and the system is built on the understanding that it can. Clearing your cookies loses your progress; it does not identify you to us any less.
If you later sign in, the runs, the tokens and the hunts that identifier collected are attached to your account, so signing up does not cost you the afternoon you already walked.
rok_did — the device identifier above. First-party, HTTP-only, one year.
rok_sid — your session, if you sign in. An opaque random value; the real session lives in our database, and only a SHA-256 hash of the cookie is stored there. It expires on its own and is revoked when you sign out.
rok_oauth and rok_pkce — two values that exist for ten minutes while a sign-in is in flight, to prove the round trip came back to the same browser that started it. Single use, then cleared.
rok_locale — which of the three languages you chose, set only when you press the switcher.
There are no advertising cookies, no analytics cookies, and no cookies set by anybody but us.
Sign-in is Google or Apple only. There are no passwords here, no one-time codes and no recovery flow, so there is no password of yours for us to hold or lose.
What the provider hands us is a stable subject identifier, an email address, and a first and last name where the provider supplies them. Apple supplies a name exactly once, on the first authorisation, and never again. We store the subject identifier, the email and the names; the subject identifier is the key, because emails change and it does not.
If you use Apple’s Hide My Email, the relay address is stored and flagged as a relay, and it is never used to match you to any other account.
We send no email. There is no password reset, no receipt, no newsletter and no digest, so the address on your account is a label on a row and nothing is ever delivered to it.
Your display name — a first name — appears on any post you write, any picture you add to a hunt’s wall, and the roster of a hunt you have joined. So does your avatar, which is either one of the app’s own motifs or a photograph you uploaded.
Your first name, last name and date of birth are read by nobody but you. They are served on one endpoint, behind your own session, marked never to be cached, and they appear in no public projection anywhere in the system. Your email address is never published either.
Coordinates of stations you have not yet found never leave the server in any form, for anybody. That is a rule about the hunt rather than about you, but it is the same rule that keeps a found station’s exact position out of a page a stranger can read.
Each run keeps an append-only log: a code was scanned, an answer was wrong, an answer was right, a token was kept, a station was visited, a hint was opened, a hunt was completed. Wrong answers are recorded on purpose — they are how a broken puzzle gets found.
That log is what the progress bar, the completion rules and the rewards are computed from. Nothing in it is deleted; a status is a reading of the log, not a column that gets overwritten.
Timestamps are stored in UTC and shown in Phnom Penh time.
Reporting a picture or a post stores one row: which thing you reported, which of the seven reasons you chose, anything you typed in the box, and that it was you. It is read by the person who runs ROK!. One report per person per thing is kept, so pressing it again changes nothing and adds nothing.
Blocking somebody stores one row saying that you blocked them, and when. They are not told, and nothing anywhere shows them that it happened — the only thing they could notice is that your pictures are no longer on a wall they are reading, which looks exactly like your not having posted any. Lifting a block keeps the row and marks it lifted, because nothing here is deleted.
Neither is published. A report is visible to nobody but the person who reads them; a block is visible to nobody but you, on your own profile.
Every photograph you upload — a post, an avatar, a picture on a hunt’s wall — is decoded, rotated to its correct orientation, resized and re-encoded before it is stored. Metadata does not survive that: the EXIF block, including any GPS tag your camera wrote, is gone before the file reaches storage. The re-encode is what makes that thorough, because no part of the original container survives it.
The stored filename is a random UUID, chosen so the order photographs arrived in is not published by their names.
Anybody holding the URL of a stored photograph can load it. There is no per-viewer check on the bytes. Hiding a picture takes it off the wall; it does not take it off the internet, and somebody who already had the link keeps it.
The website never sends your location to our server. Two screens can sort hunts by how near they are, and both ask your browser for a position only after you press the control that says so, at low accuracy, and use it in the page. It is not stored and not transmitted.
In the phone app, location is foreground-only and asked at the moment of the tap. It is used for one thing: an author placing a station taps the control that says to use where they are, and the pin lands there. That coordinate becomes part of the hunt, which is the one place a position deliberately travels into the system. Background location is switched off in the app’s configuration.
Maps on the website are drawn with Leaflet over tiles from tile.openstreetmap.org. Loading a map therefore tells the OpenStreetMap Foundation your IP address and which tiles you looked at, the same as any site using their tiles. Nothing about your account, your run or your progress goes with that request.
The phone app uses Google Maps instead, and Google’s own terms and privacy policy apply to that.
Both are published by the people who run them rather than by us: the OpenStreetMap Foundation’s policy is at osmfoundation.org/wiki/Privacy_Policy, and Google’s is at policies.google.com/privacy. They are written as addresses rather than as links because this document is rendered inside the app as well, where there is nothing to tap.
This is worth stating flatly, because most sites cannot. There is no Google Analytics, no Plausible, no PostHog, no Mixpanel, no Amplitude, no Sentry, no Firebase, no Vercel analytics, no session recorder and no telemetry of any kind — not in the website, not in the API, not in the phone app, not in any shared package. Nothing counts your visits and nothing profiles you.
Fonts are downloaded when the site is built and served from this site, so rendering a page makes no request to a font provider.
The one number the app shows you — the unread badge — is computed from your own run log when you open the app, against a marker your own device keeps. Nothing is delivered to you and there are no push notifications.
The FAQ and the feedback form are provided by SupportDock, whose own terms and privacy policy are at supportdock.io. Sending feedback sends them your message, the optional name and email you typed, the page you were on, and the first 160 characters of your browser’s user-agent string. If you attach a screenshot it is decoded, stripped of metadata and re-encoded before it leaves our server; an attached video is size-checked but not re-encoded.
You do not need an account to send feedback, and if you leave the email box empty we have no way to reply.
The API limits how often a single address can scan codes, submit answers and send feedback. Those counters live in the running process’s memory and are forgotten when it restarts. No IP address is stored in the database — the only thing like it that is stored is the browser user-agent string on a session row, which is there so a session can be recognised.
Everything runs on a single rented virtual server from OVH: the API, the website, a PostgreSQL database and Redis. Photographs are stored on that server’s disk. There is a nightly database dump on the same machine.
There is no content delivery network in front of it and no object storage behind it. That is worth saying because most sites have both, and both would mean your requests passing through somebody else’s infrastructure; here they do not.
Nothing is kept for a fixed period, and the honest way to put that is that everything is kept indefinitely. The event log a hunt is built on is append-only by design — a status is a reading of the log rather than a column that gets overwritten — so there is no expiry job, no archive step and no retention window to quote. Closing your account is the one thing that removes anything, and the section on it says exactly what it removes and what it does not.
The website installs a service worker, and it caches two things: build files whose names contain their own content hash, and four icons plus the offline page. It never caches a page, never caches a response from the API and never caches a photograph, and it refuses to store anything a server marked private or no-store. Nothing about you is held in it.
The phone app keeps your device identifier and your unread marker in ordinary app storage, and your session token in the platform’s secure keystore.
You can close your account from the profile screen, on the website or in the app. It is worth reading what that does before you sign in, because it does not mean everything is erased.
What goes: every link to your Google or Apple identity, your display name, your avatar, your first name, your last name and your date of birth. Every session is revoked, on every device. Your pictures come off every hunt wall.
What stays: your runs, the events in them, the tokens you claimed, the rewards you were issued, and any post you wrote. The log is append-only, and a claimed token’s page is a permanent public record of that object — one post, forever, by design. Those records survive without your name on them.
Signing in again afterwards with the same Google or Apple account creates a new, empty account. It does not bring the old one back, and there is no way to bring it back.
If you delete your Apple ID, Apple tells us, and we run exactly the same closure.
The feedback form on the help page reaches a person. It is the way to ask anything in this document — what is held about you, why, or to ask for it to be removed.
The one removal this system performs on its own is closing your account, and the section above sets out exactly what that takes away and what it leaves. Anything beyond that is a conversation rather than a button, because the log a hunt is built on is append-only and a claimed token’s page is a permanent public record of that object.
Nothing in this system asks your age or gates on it. The date-of-birth field on your account is optional, is read by nobody but you, and nothing anywhere consults it.
Playing needs no account at all, so a child can walk a hunt without anything about them existing here. An account — and with it the ability to put a picture on a hunt’s wall, which anybody can read — needs a Google or Apple sign-in, and those have their own age rules that we do not see the workings of.
The date at the top is when this text last changed.
That date is the whole of the notice, and it is better to say so than to imply more. No email is ever sent from this system — there is no address list, no newsletter and no delivery of any kind — so there is no channel to announce a change through. A material one will move the date and rewrite the text under it, and the document is reachable from the foot of every page and from the settings screen in the app.