Privacy policy
Last updated: 2026-05-12
What we collect
We collect analytics in three layers, each with a different legal basis and retention policy. The first layer is on by default; the other two are opt-in.
- Server-side visitor profile (always on, no consent required). When a page is requested, our server records one row per visitor per UTC day for each unique combination of device family (mobile / tablet / desktop), OS family, browser family, theme preference, consent state, referring host (if any), and an approximate location (country, region, and city) derived from your IP address by a local MaxMind GeoLite2 database. Your IP address is not stored and is not transmitted to any third party; only the resulting country/region/city codes are kept. The path you visit is not recorded — only the dimensions above. Repeated requests during the same day with the same dimensions are deduplicated to a single row. To avoid hitting the database on every page load, we set a short-lived first-party cookie (
vp) carrying an opaque dimension hash plus today’s UTC date; on subsequent requests with a matching cookie, no database write happens at all. The cookie is deleted at midnight UTC. Hashing uses a daily-rotating saltcombined with the IP address and user-agent. After the salt rotates at 00:00 UTC, the previous day’s salt is discarded — re-identifying a visitor across days is structurally impossible. Data stays on our own infrastructure. Legal basis: legitimate interest (GDPR Art. 6(1)(f)) — necessary for site operation and audience understanding. - First-party engagement events (only after consent).If you accept analytics in the cookie banner, the site sends a small "beacon" on each navigation (pageviews) and on significant interactions (e.g. canvas events). Each event also carries the same approximate country/region/city derived from your IP. Same anonymization, same first-party storage, same 30-day retention. Legal basis: consent (GDPR Art. 6(1)(a)).
- Google Analytics 4 (only after consent).If you accept, we additionally load Google’s
gtag.jsfromhttps://www.googletagmanager.comand Google receives event-level data on your visit (see “Third-party data processors” below). Legal basis: consent (GDPR Art. 6(1)(a)).
You can revoke consent at any time via Cookie settings. Revocation takes effect immediately on the client; the GA cookies are deleted and no further events are sent.
Newsletter subscriptions
If you subscribe to the newsletter, we store the following on our own infrastructure:
- Your email address (normalized to lowercase) and the source (which form on the site you submitted from).
- A timestamp, your IP address, and your user-agent at the time of signup. These are kept as a record of your explicit consent and are never used for anything else.
- A random unsubscribe token that we’ll embed in every email we send so you can unsubscribe in one click.
Legal basis: explicit consent (GDPR Art. 6(1)(a)). Sharing:none — we don’t share or sell the list to any third party. Retention:we keep the record until you unsubscribe, and afterwards we retain only the suppression entry (your email plus a status of “unsubscribed”) to make sure you don’t get re-added by accident if a bulk import is ever run. If you want the record fully deleted, contact the address listed in security.txt and we’ll remove it.
How to unsubscribe: every newsletter email carries a one-click unsubscribe link. You can also visit the unsubscribe page directly if you have your token.
Third-party data processors
We use one third-party processor, only after explicit consent:
- Google Analytics 4 (Google LLC, USA). Used for audience and engagement reporting. Data transferred to the United States under the EU-U.S. Data Privacy Framework / Standard Contractual Clauses. Google receives: page path, page title, page referrer, anonymized IP (anonymization is automatic in GA4), device / OS / browser, language, screen size, timezone, GA4-synthesized session/user identifiers stored in the
_ga/_ga_*cookies, and the custom events we emit (lesson_view,select_content,r3f_canvas_loaded,blog_read_progress) with their parameters. Google retains this data for 14 months (per our admin setting). Google Signals is disabled, so Google account data is not joined to your visit.
Google’s privacy policy: policies.google.com/privacy.
Retention
Raw analytics events and visitor-profile rows are both kept for 30 days (enforced by TTL indexes in our database). Daily aggregate counts are kept indefinitely; they contain no per-visitor data — only counts per path per day.
Audit logs (administrator actions on the site) are retained for compliance purposes and contain no visitor data.
Cookies
Essential (always set, first-party):
theme— your light/dark preference.consent— records your cookie-banner choice.vp— visitor-profile dedup marker (opaque dimension hash plus today’s UTC date). HTTP-only; expires at the next 00:00 UTC. Carries no identity and is not used for cross-site tracking.sid— administrator session cookie. Only set if you sign in to the admin dashboard.
Third-party (only after consent):
_ga— Google Analytics. Distinguishes unique visitors. Lifetime 2 years._ga_<property>— Google Analytics. Per-property session state. Lifetime 2 years.
Your rights (EU/EEA visitors)
Analytics data is anonymized with a daily-rotating salt and is not tied to your identity, so there is no per-visitor record we can hand back or delete. If you have a newsletter subscription or an admin account, those records ARE tied to your email — contact the site operator to access, rectify, or delete them. For newsletter, the simplest route is to use the unsubscribe link in any email; for full deletion, write to the address in security.txt.
Contact
For questions about this policy, see security.txt.
This policy describes the actual technical posture of the site and is intentionally specific, not a template. Updates are versioned in this site’s git history.