privacy

last updated: 2026-05-16

This is the plain-language version of what sonderframe.works (the site) collects about visitors, why, and how to make it go away. The behavior described here matches what the code actually does. If you ever find a discrepancy, that's a bug — please tell me at young@sonderframe.works and I'll fix it.

tl;dr

what I collect

edge request logs (every visitor, including EU visitors who made no choice)

FieldDetail
tsWhen the request happened, millisecond precision (UTC).
Country, region, cityDerived from your IP by Cloudflare. Used for geographic aggregates.
ASN / network operatorHelps distinguish university/ISP/datacenter traffic.
User-AgentYour browser / OS, or the bot's identifier.
Referer (hostname only)e.g. google.com — not the full URL.
Path requested, status code, response size, response timeStandard HTTP log fields.
anon_hashAn irreversible SHA-256 hash of (IP + UA + today's date + a secret salt), truncated. Resets every UTC midnight, so I can recognize repeat hits within a day but cannot tie one day to another for non-consenting visitors.
ClassificationOne of human, verified_bot, ai_crawler, unknown_bot, suspicious. Computed from the user-agent and Cloudflare's bot signals.

IP addresses

I store your IP address only if (a) you're outside the EU/UK/EEA, or (b) you chose Allow on this page. Otherwise the IP is used once to compute anon_hash and is never written to disk.

behavioral events (only with consent or outside EU)

A small script sf.js on each page sends additional data about how you read:

This data is associated with your _sf_vid cookie (a random ID, see below).

session recordings (Microsoft Clarity) — the taster only, with consent or outside the EU

On the taster (the interactive page at the root of this site), a third-party recorder, Microsoft Clarity, records how the page is used: where you tap, how you swipe, what the page showed at the time. It is the one third-party script on this site, and it runs only:

An EU visitor who has made no choice is never recorded. Text you type is masked before it leaves your browser. Clarity sets its own cookies (_clck, _clsk) to tell one session from the next; Microsoft's own privacy statement governs what it keeps, and I keep recordings for the shortest period Clarity offers. What I use them for: to see why a visitor stopped where they did. The recorder is tagged with the same anonymous session key as the events above, never with an email or a name.

cookies (only with consent or outside EU)

CookiePurposeLifetime
_sf_vidRandom visitor ID, used to recognize you across visits. Not linked to any external profile.1 year
_sf_sidRandom session ID, used to group requests within ~30 minutes of activity.30 minutes, sliding
_sf_consentStores your choice from this page (granted or denied).1 year

None of these are HttpOnly because the analytics script reads them. None are third-party; the session recorder's own two cookies are listed in its section above. All are SameSite=Lax.

browser storage (the web taster)

The taster stores seven small things in this site’s own browser storage, and nowhere else. tfw.visits is a number: how many times this browser has opened the taster. tfw.exp.<id> (today tfw.exp.word1) records which version of the entrance this browser was shown, as a short arm name and the date it was drawn, so that a second visit is not a different experience from the first. tfw.exp.price1 recorded, until 16 September 2026, which version of the store page — whether it showed the price — this browser was shown; the price is no longer shown to anyone, a browser that holds the key keeps it, and nothing reads it any more. tfw.hint.swipe and tfw.hint.card each record that this browser has already been shown one of the two small one-time hints — the picture leaning to show that it can be swiped, and a small mark on the card to show that it can be touched — so that neither is shown again once you have done the thing it was pointing at. tfw.hint.pill and tfw.hint.pill.stage record that the short written instructions on the picture (“swipe all the way”, and the ones that follow it) have been shown and how far you got through them, so neither is shown twice. The sound is off on every visit, and the butterfly that shows you where it is turned on comes every time; nothing about either is stored. (A key named tfw.hint.butterfly, which existed for one afternoon, is deleted on your next visit.) Neither is an identifier. They say nothing about who you are, they cannot be read by any other site, nothing is shared with anyone else, and the only part of them that ever leaves the device is that one short arm name on my own anonymous measurement, which carries no identifier of any kind. Clearing this site’s data in your browser removes them. The app itself keeps nothing of the sort.

ad click ids

If you arrive from one of my own Google ads, the address carries a click identifier Google adds (a gclid). The taster keeps it in memory for that page load only, never in storage, strips it from the address bar at once, and records it on two of its own events: the arrival, and a tap on a store button. Once a week I send those store-button taps back to Google as conversions, so the ads can be read honestly. Visitors in the EEA, the UK and Switzerland are excluded from this at the server before anything is stored. No pixel, no script from Google, and nothing about who you are.

what I do not collect

the mobile app (Thought-filled Words)

The Thought-filled Words app (iOS and Android) sends me two kinds of data. The behavior described here matches what the code actually does, same rule as above.

crash reports (Sentry)

If the app crashes, a crash report goes to Sentry so I can fix it. It contains the stack trace, app version, OS version, and device model — no name, no email, nothing you typed.

usage events (first-party, my own server)

The app records which parts of it get used — a word was viewed, the opening was skipped, the info panel was opened, a setting was changed, the purchase page was reached, a download finished — plus a few health signals (how long the app took to start, whether memory ran low), and whether a tap on the purchase page’s buttons registered — no content, no identifiers. Each event carries the app version, OS version, device class (phone or tablet), and the app's display language.

These events are tied to a random install ID — a number the app makes up the first time it runs. It is not your advertising ID, not your device serial, not derived from anything about you, and deleting the app deletes it. I cannot connect it to you, and I don't try.

The events go to the same infrastructure as the site's analytics (my own VPS — see "who has access"). No IP address and no location are stored with app events — the server writes only what the app sent. There are no advertising SDKs, and nothing is sold or shared for advertising. The one third-party analytics SDK is the session recorder described below.

which free chapter (Android, first launch)

On its first launch, the Android app asks my server which free chapter to show. The request carries no identifier: only a number from 0 to 5 and the version of the app's content. The server reads the country of the network the request came from, uses it to answer, and keeps no record of the address. What it keeps is a count: how many first launches in each country were shown each chapter.

session recordings (Microsoft Clarity) — Android, outside the EU/UK/Switzerland

Since the free-to-install build of late September 2026, the Android app carries the Microsoft Clarity recorder, the one third-party analytics SDK in the app. It reconstructs what the screen showed and where you tapped and swiped, so I can see where a stranger stopped. It starts only when the phone's own region setting is outside the EU, the UK, Iceland, Liechtenstein, Norway and Switzerland — the app never looks up where you are from your network address. A phone set to one of those regions is not recorded at all until the app offers a switch for it (planned) and you turn it on. The recording is tied to the same random install ID as the usage events above, never to a name, an email or an advertising ID; there is nothing to type in the app, so nothing typed can be captured. Microsoft's own privacy statement governs what Clarity keeps; I keep recordings for the shortest period it offers. The iOS app does not carry it.

what the app does not collect

app data retention

App usage events are kept for 2 years (a ClickHouse TTL enforces this), then deleted automatically.

Google account data (the advertising tool)

Sonder Frameworks advertises the app with Google Ads. To manage those campaigns I run a small command-line program of my own that signs in to Google with my own Google account and, through the Google Ads API, reads and edits my own advertising account: the campaigns, keywords, ads and their performance reports. That is the only Google data it touches.

why I collect it

legal basis (GDPR speak)

how long I keep it

who has access

Just me. No third-party analytics processors, no data brokers. The data lives on a small VPS I rent and on Cloudflare R2 (for backups). No data is shared, sold, or sent to advertisers.

Cloudflare and the VPS host are technical sub-processors: they handle bits flowing across their wires, not analytics queries.

your rights (GDPR / UK-GDPR / CCPA)

Contact for any of the above: young@sonderframe.works. I'll respond within 30 days as required by GDPR (and usually much sooner).

changes

If I change this page in a way that materially changes what's collected or who has access, I'll bump the date at the top and explain the change here.

← back to sonderframe.works