← stijn.tf

Privacy

The opening of this site demonstrates what a normal web page can observe. This page explains exactly what happens, what is honestly unavoidable, what stijn.tf now keeps, and what it deliberately refuses to. No impossible promises, and no claim on this page that the code does not actually honour.

The short version

Precise device location never leaves your browser's memory, is never sent to the server, and is never written to any persistent store. That part has not changed and will not.

stijn.tf does now keep first-party analytics, and this page would be worthless if it did not say so plainly. It records how pages are read — which sections hold attention, how long the intro takes, roughly which city the connection is in — and it keeps that as individual visit records rather than only as totals. Your IP address is truncated to its network before it is stored and is never kept in full. There is no advertising, no third-party tracker, no session replay, and nothing is ever sold or shared.

There is no cookie banner, and that is a design decision rather than an oversight. The identifier this site derives rotates every day, so no visitor can be recognised tomorrow as the same visitor who came today. With nothing persistent to consent to, there is nothing to ask you to agree to. The section below spells out exactly how that works.

If your browser sends Global Privacy Control or Do Not Track, nothing is recorded at all. DNT is legally binding nowhere and is honoured here anyway.

Network metadata

Making any HTTPS request necessarily reveals your IP address to the hosting infrastructure (Railway, and Cloudflare if it fronts the site). From that connection, a coarse, IP-derived location and the network routing your traffic (ASN) can be estimated. This is inherent to the request, so it needs no permission.

The /api/context endpoint returns only this coarse estimate, labelled NETWORK ESTIMATE, with Cache-Control: no-store. Your IP address is shown back to you in the demonstration, only ever to the visitor it belongs to, in the response to your own request. That is not a disclosure: your browser already knows it, and every server you contact receives it. Showing it is the point. The full address is never written to any database. What the analytics store keeps is the address truncated to its network, and a keyed one-way hash derived from that prefix — see “Analytics, in detail” below. To derive the estimate the server queries several free, keyless IP-geolocation databases in parallel, among them ipwho.is, ipquery.io and geojs.io, and keeps the position they agree on, because any one of them is routinely wrong by tens of kilometres. They receive your IP address and nothing else. Your browser's IANA timezone is sent to /api/context as well, to discard answers that contradict it; it cannot locate you and is not stored. Answers are held in server memory for five minutes under a salted hash of the address, never the address itself, so a refresh does not re-query. No GeoIP provider ever receives your precise device location.

Browser metadata

On page load the site reads standard, documented Web APIs: viewport and screen size, device pixel ratio, logical CPU count, approximate device memory where supported, language and timezone, colour scheme and reduced-motion preferences, WebGL availability and the GPU renderer string where the browser exposes it.

It does not perform canvas or audio fingerprinting, and it does not compute a persistent fingerprint from any of this.

Some of it is transmitted and stored, and it would be a strange page to lie on. When analytics is permitted, viewport and screen size, device pixel ratio, CPU count, approximate memory, language, timezone, colour scheme, reduced-motion preference and the GPU string are recorded against the visit. Three of those — browser family, operating system and primary language — also feed the keyed hash that counts returning visitors. The rest is stored only as description, never as identity. When analytics is refused or has not been granted, none of it leaves the page at all: the readouts in the intro are rendered from values that stay in browser memory.

Precise device location

The intro never asks for this on its own. It checks, via the Permissions API, whether you have already granted location to this origin: if you have, reading it raises no dialog and the exact fix is used; if you have not, the demonstration stays on the coarse network estimate and the choice is left to a button. Pressing that button triggers your browser's own permission prompt. The prompt is the browser's, and no site (this one included) can bypass it. If you decline, the demonstration continues with the coarse network estimate only. When granted, the result (latitude, longitude, accuracy, and any altitude/heading/speed your device reports) is held in short-lived React state only.

It is never POSTed to the server, never placed in a URL, query string, cookie, localStorage, sessionStorage, database, analytics, or crash report. Forget my location stops any active watcher and clears it from memory immediately.

Map & 3D imagery providers

Before you grant location, the geographic view is rendered entirely in your browser on a canvas, as an abstract instrumentation view rather than a real photo of your street, and contacts no third party.

After you grant precise location, the 3D descent shows real streets and buildings around that position. Rendering that view necessarily fetches map tiles for the area. By default this uses OpenFreeMap (free, keyless vector tiles) built from OpenStreetMap data; those tile requests reach tiles.openfreemap.org. Only the approximate area needed to draw the view is involved, and your precise coordinates are used solely in your browser to aim the camera. They are not sent as data to the tile server.

If a Google Maps key is configured instead, the site uses Google Maps Platform for photorealistic 3D. Required attribution is always preserved in the view either way.

Infrastructure processing

Application-level non-retention is not the same as no processing anywhere. Hosting and network providers maintain their own standard operational and security logs independently of this application:

stijn.tf's own logs are operational only (e.g. "GeoIP provider unavailable") and never contain precise coordinates, addresses, accuracy values, or a reconnaissance payload. The analytics database is separate from those logs and is described above.

Analytics, in detail

What is recorded, when consent allows it: the pages and sections you view and how long each was actually on screen; how far down you scrolled; where presses land, as a coordinate on a grid; how far through the intro you got, including whether you granted precise location and whether you then deleted it; the page or assistant you arrived from; and your browser, operating system, device class, language and approximate city.

How you are identified: not by name, cookie, or fingerprint — and not across days. Your IP address is truncated to its network (the first three octets of an IPv4 address, the first three groups of an IPv6 one). That prefix, your browser family, operating system, primary language and today's date go through a keyed one-way hash under a secret held only on the server.

The date is the part that matters. At midnight UTC the input changes, so the same person visiting on two consecutive days produces two unrelated values with nothing linking them. There is no way, from this data, to ask what any individual did over a week. That capability was deliberately removed, and it is what a claim of "we don't track you" has to mean if it is going to mean anything.

The honest cost, since a privacy page is the wrong place to only list upsides: the site genuinely cannot tell a loyal reader from a first-time one beyond the end of the day, and returning visitors means "came back later the same day". The full address is never written to any database, and no canvas, audio or font fingerprinting is performed at any point.

Also recorded, because they are useful and it would be strange to list everything else and omit them: the page-speed measurements your browser reports (Largest Contentful Paint, Interaction to Next Paint, Cumulative Layout Shift), how long after arriving you first pressed something, presses that landed on nothing interactive, and repeated presses in the same spot. That last pair exists to find parts of this site that look clickable and are not.

What is measured about hang time is only the time the tab was actually visible. A page left open in a background tab does not count as reading, because reporting it as reading would be a lie I would be telling myself.

Where it lives: a Postgres database on Railway, in the same private project as the site. It is not shared with any analytics vendor, because there is no analytics vendor — the whole pipeline is in this site's own source.

Your choices

Refusing. Turn on Global Privacy Control or Do Not Track in your browser and this site records nothing about your visit. Both are checked before a single byte leaves the page, so this is not a request that gets honoured later — nothing is sent in the first place.

Browser-level opt-out. Global Privacy Control is honoured everywhere, not only where it is legally binding. Do Not Track is honoured too, even though it is not binding anywhere — a site that argues about surveillance for a living should not need to be forced.

Erasure. Email [email protected] and it is deleted. Because nothing here identifies you, the honest caveat is that I may need you to tell me roughly when you visited in order to find the record — the same anonymity that protects you is what makes it hard to look you up.

What is still never done

  • No advertising, and no third-party trackers of any kind
  • No session replay — no recording of your screen or cursor
  • No canvas, audio or font fingerprinting
  • No raw IP address stored, ever
  • No precise device location stored, ever
  • No selling, sharing or transfer of any of it to anyone
  • No storing anything for a visitor who was asked and said no

Contact

Questions about any of this: [email protected].