Privacy Policy
Last updated: 2026-08-05
This is a draft prepared for review. It has not been reviewed by a qualified lawyer.
By default, your training data never leaves your device. Not encrypted-and-uploaded — not uploaded. There is no copy of your practice history on our servers unless you choose to create an account and switch sync on.
That is a design decision, not a marketing line: the trainer stores everything in your browser's own database and keeps working with the network off. This policy explains exactly what is stored where, field by field, and what we never collect.
Contents
- What "local-first" means
- What is stored on your device
- What is sent if you create an account
- What we never collect
- Website analytics
- Cookies and browser storage
- Who else touches the data
- Export and deletion
- Your rights (UK/EU GDPR)
- How long we keep things
- Security
- Children
- Changes to this policy
- Contact
1. What "local-first" means
The CountLab trainer runs inside your browser. Your progress is written to IndexedDB — a database the browser provides, stored on your own machine — using a library called Dexie. There is no background upload. After the first visit the app keeps working offline, because everything it needs is already on your device.
What that means in practice:
- We cannot see your practice history. Not "we choose not to look" — there is nothing to look at, because it was never sent.
- Your data is tied to that browser on that device. Using a different browser or a different computer starts fresh.
- If you clear your browser's site data, uninstall the browser, or use private/incognito mode, your progress goes with it. We cannot recover it, because we never had it. Export is how you keep a backup.
2. What is stored on your device
The browser database holds, roughly in order of how much of it there is:
- Your decisions. One row per hand you play: the skill it belongs to (for
example
bs:hard:16:10), the dealer upcard, the action you chose, the correct action, the EV cost of the difference, how long you took in milliseconds, a timestamp, which session and rule set it belonged to, and whether you have flagged it for review. - Your skill states. One row per decision cell: the spaced-repetition state (difficulty, stability, when you last reviewed it), a short list of recent attempts, your curriculum stage, an EV-impact estimate, and when the cell is next due.
- Sessions — start and end times and the random seed used to deal, which is what makes a session reproducible.
- Rule sets you have configured or saved, and the strategy tables computed for them (a cache — regenerable, and left out of exports for that reason).
- Preferences and profile — drill timing, your active rule set, and a marker that you have finished the first-run walkthrough.
- Session goals you set, while they are open.
- Sync bookkeeping, only once accounts ship and only if you sign in: a device identifier this app generates for itself, a refresh token, sync cursors, and the last sync time.
None of this is sent anywhere by the app on its own.
3. What is sent if you create an account
An account is optional and exists for one reason: to sync progress between your own devices. If you never create one, this whole section does not apply to you. Account sign-up not yet live
The server side is built and the fields below are exactly what its database defines; the in-app sign-up and sync controls ship in a later release. When they do, this is the complete list of what is stored on our server — nothing else.
| Field | What it is |
|---|---|
| The address you sign up with, normalised to lower case. This is the only contact detail we hold. | |
| password_hash | An Argon2id hash of your password. We do not store the password itself and cannot read it. |
| id, sync_seq, created_at, updated_at | An internal account identifier, a counter used to order sync updates, and timestamps. |
| Field | What it is |
|---|---|
| device id, last_seen_at | An identifier your own app generates for each device (not a hardware ID, not an advertising ID), and when it last synced. |
| token fingerprints, expiry and timestamps | SHA-256 fingerprints of your access and refresh tokens — never the tokens themselves — plus when a session was created, last used, expires, and whether it was revoked. |
| Field | What it is |
|---|---|
| skill_id, category, stage | Which cell (e.g. hard 16 vs 10) and where it sits in the curriculum. |
| fsrs | Scheduling state: difficulty, stability, last review time. |
| recent_attempts | A short rolling list: correct or not, latency in milliseconds, and when. |
| ev_impact, due_at | How costly this cell's errors are, and when it is next due. |
| client_updated_at, version, server_seq | Bookkeeping used to merge changes from two devices without losing practice. |
| Field | What it is |
|---|---|
| skill_id, period | The cell, and the calendar month in YYYY-MM (UTC). |
| attempts, correct | How many attempts that month and how many were right. |
| ev_cost_total | Total EV cost of the mistakes in that bucket. |
| latency_buckets | A histogram of response times — counts per band, not individual timings. |
| device_id, client_updated_at, version, server_seq | Bookkeeping, as above. |
Your individual hands never leave your device. There is deliberately no table on the server for raw decisions. The monthly rollups above are the aggregate the sync feature needs; the hand-by-hand history stays local. This is enforced in code — the sync protocol has no message that could carry a raw decision, and an automated test fails the build if a migration ever adds such a table.
4. What we never collect
- No money, ever. CountLab has no wagering and no real currency. We do not ask how much money you have, do not record any bankroll in currency, and hold no record of any gambling you do.
- No sale of data. We do not sell, rent, or trade your data. There is no version of this business where we do.
- No advertising trackers. No ad networks, no advertising pixels, no remarketing tags, no data brokers.
- No cross-site tracking, no fingerprinting, no session recording, and no third-party analytics beyond the one tool described below.
- No casino or operator integrations. No affiliate links, no referral revenue, no operator partnerships — so there is nobody to share data with even in principle.
- No unnecessary personal details. No name, no address, no date of birth, no phone number, no payment card details held by us.
5. Website analytics
We use Cloudflare Web Analytics on the CountLab website to see whether the site is working and where visitors come from. Enabled at launch
What it is, accurately:
- Cookie-less. It does not set cookies and does not store or retrieve anything on your device to identify you.
- No cross-site tracking and no per-person profile. It does not follow you to other websites and does not build a profile of you.
- Aggregate only. It reports counts: page views and visits, referring sites, country, browser and device type, and page-load performance. We see totals, not people.
- Limited by design. The data is sampled over longer time ranges and retained for around six months. It supports no custom events, no funnels, and no individual-level retention analysis — and we are not adding a second tool to work around that today.
We do not use Google Analytics, Meta pixels, heatmaps, or session-replay tools. If we ever add in-product analytics, this policy is updated first and the entry will say exactly what is measured.
6. Cookies and browser storage
We use no tracking cookies. That is why there is no cookie banner — and it is the honest reason, not a technicality. Under UK/EU rules, consent is required for storage that is not strictly necessary for a service you asked for. Our analytics sets nothing at all, and the only storage we use is the app's own database, which exists solely to deliver the trainer you opened.
What the app does store on your device:
- IndexedDB — your training data (section 2). Strictly necessary: without it the trainer cannot remember anything, and it is on your machine, not ours.
- Cache storage / service worker — the app's own files, so it loads fast and works offline.
- Sign-in tokens, only if you sign in, kept in IndexedDB rather than cookies. The short-lived access token is held in memory only and is never written to disk.
You can clear all of it at any time through your browser's site-data controls.
7. Who else touches the data
Only the suppliers needed to run the site, each acting on our instructions under a data processing agreement:
- Cloudflare — hosting and content delivery for the website and app, plus the analytics described above. As with any website, connection information such as your IP address is processed by the hosting layer to deliver pages and to block abuse.
- Neon — the managed Postgres database that stores account and sync data, if you create an account. Live when accounts ship
- A payment processor — only if and when paid plans launch. Card details would go to them and never to us. Not in use
On IP addresses specifically: our own API can use your IP address, together with the email address being tried, to rate-limit sign-in attempts — but only where a trusted proxy is configured, it is held briefly in memory, and it is not written to our database or attached to your account.
We will also disclose data where the law genuinely requires it. We have never received such a request; if that changes, we will tell affected users where we are permitted to.
The site is served by Cloudflare from its global edge network, so the copy of these pages you receive is delivered from a location near you rather than from a single country. If and when accounts launch, the database will be hosted by Neon. Data may therefore be processed outside your country, including in the United States. Where that happens it relies on the safeguards those providers have in place. Cloudflare certifies to the EU–US, Swiss–US and UK extension of the Data Privacy Framework and incorporates the European Commission's standard contractual clauses in its data processing addendum. Neon (now part of Databricks) provides a data processing agreement that likewise incorporates the 2021 standard contractual clauses.
8. Export and deletion
Export Built
In the app's Progress area you can export:
- Decisions as CSV — every hand you have played, one row each.
- Everything as JSON — decisions and skill states together. Cached strategy tables are excluded because they are regenerable from your rule set.
Both are plain files saved by your browser. No account, no request to us, no waiting.
Deleting local data Built
Your data is on your device, so you delete it there: clear site data for CountLab in your browser's settings, and the database goes with it. We are not involved and cannot undo it.
Deleting a server account In-app control ships with accounts
Deleting your account removes your account row and, by database cascade, every device record, sign-in session, skill state, and rollup attached to it. The deletion endpoint is already built and tested on the server; the button that calls it arrives with the account interface. Until then, you can email us and we will do it — see Contact. Deleting the server copy does not touch the copy on your own device.
9. Your rights (UK/EU GDPR)
The data controller is [PLACEHOLDER — data controller identity and registered address, owner to confirm].
Lawful bases we rely on:
- Performance of a contract — holding your email address, password hash, and synced progress so that the account and sync features you asked for can work.
- Legitimate interests — aggregate, cookie-less visit statistics to understand whether the site works, and security measures such as rate limiting. We have weighed these against your interests; the data is minimal and identifies nobody.
- Legal obligation — where we must keep records, for example tax records once paid plans exist.
Your rights. You can ask for access to your data, correction of it, erasure of it, a portable copy, restriction of processing, or object to processing based on legitimate interests. Because the trainer is local-first, you can exercise access, portability, and erasure yourself and immediately — export and clear, above — without asking anyone's permission. For anything held on our server, email us and we will respond within one month.
If you are unhappy with how we handle a request, you can complain to your data protection authority — in the UK that is the Information Commissioner's Office (ico.org.uk); in the EU it is your national supervisory authority.
10. How long we keep things
- Local data — until you delete it. There is no expiry and no automatic clean-up by us.
- Account and synced data — until you delete your account.
- Sign-in sessions — token records expire on their own schedule and are revoked when you sign out.
- Website analytics — aggregate figures, retained by Cloudflare for roughly six months.
11. Security
The measures actually in place: passwords are stored as Argon2id hashes and never in readable form; sign-in tokens are stored only as SHA-256 fingerprints, so a copy of our database contains no usable token; refresh tokens are grouped into families so that reuse of a stolen token revokes the whole family; sign-in attempts are rate-limited; and everything travels over HTTPS. The short-lived access token stays in memory on your device rather than being written to disk.
Honestly: no system is perfectly secure, and we do not claim otherwise. The strongest protection here is structural — most of your data is never on our server at all.
There is currently no password-reset email flow. If you lose your password we cannot restore access to the synced copy of your progress. The copy on your device is unaffected.
12. Children
CountLab is for adults only — 18+, and 21+ where that is the legal gambling age. It is not directed at children, we do not knowingly collect data from anyone under 18, and if we learn that we have, we will delete it. If you believe a child has created an account, contact us.
13. Changes to this policy
If what we do changes, this page changes first — before the new behaviour ships, not after. The "last updated" date at the top always reflects the current version. For significant changes we will post a notice on the site, and email account holders.
14. Contact
Privacy questions, or to exercise any right above: [PLACEHOLDER — support email, owner to confirm].
See also the Terms of Service.