When a visitor declines tracking, your analytics stops counting. Your traffic doesn’t.
INSIGHTS measures the operational shape of non-consented traffic: volume, geography, device mix, bot pressure and performance. None of it requires holding an identifiable record in the operational lane. Raw bot signals stay in a separately keyed security lane under a 7-day TTL, and only a bot label plus its confidence may cross back.
No cookies · No fingerprinting · No visitor, session or event query surface
One group withheld: below the suppression threshold. Never inferred, never back-filled.
A consent banner splits your traffic in two. Only one half is measured.
Everything downstream of the banner inherits the split. Capacity planning is sized on partial demand. Bot and abuse pressure is assessed against a fraction of real load. Performance regressions in a region you cannot see stay invisible until the support tickets arrive. Board-level traffic figures carry an unstated caveat that nobody has quantified.
Most teams respond by applying a fudge factor, or by quietly weakening the consent boundary. The first is unaccountable. The second is the thing your DPO exists to prevent.
There is a third option: measure the aggregate shape of that traffic in a way that is structurally incapable of identifying anyone, then prove the structure holds.
Every figure tells you whether it was counted or estimated.
Windowed unique reach uses fixed-precision p=14 HyperLogLog sketches and displays RSE ±0.81%. Request counts are measured counters. Extending unique reach across windows is impossible by design because the salt is destroyed at every boundary. Monthly figures are therefore modelled, and always carry a 90% interval.
Illustrative figures. HLL estimates show their relative standard error, measured counters are labelled measured, and violet modelled values never appear without their interval. The dashboard uses the same distinction: unique reach takes the estimate path with an interval; counted request metrics remain band-free.
Three lanes that cannot reach into each other.
Lane separation is enforced at the data-flow level, not by convention. A lane is a distinct set of services, storage partitions and keys.
Consented lane
Ordinary first-party analytics for visitors who agreed. Its only export into the rest of the system is a set of aggregate coefficients, never a per-visitor row.
Operational lane
No client storage, no fingerprinting and no raw-event persistence. A token derived at the edge updates a HyperLogLog sketch, then the token, truncated IP and raw user-agent are zeroised.
Security lane
Isolated bot scoring with its own 7-day store and its own keys. It may pass only bot_label and confidence into the operational lane.
The strongest guarantee is a question with no endpoint.
These routes don’t exist, and a test asserts they never come back. There is no visitor row anywhere in the system for them to return.
GET /visitorsGET /sessionsGET /eventsGET /subjectGET /lookupGET /export/raw
Asserted by INV-012 against the canonical OpenAPI contract on every commit.
Twelve invariants. Each one blocks the release if it fails.
The compliance argument stops being a document someone wrote and becomes a property of the build that CI re-checks on every commit.
No client-side storage
The browser beacon touches no cookie, no localStorage, no sessionStorage, no IndexedDB. Asserted by walking the minified bundle's AST, not by grepping source.
No fingerprinting inputs
No canvas, no audio context, no font enumeration, no hardware or screen interrogation. The event schema is a closed allowlist with additionalProperties: false.
The dedup token is never persisted
It exists in process memory for milliseconds, then is zeroised. A nightly sweep greps every database column, log stream and trace export for known token values.
Aggregate-only, k-thresholded
No response schema permits an array of per-visitor objects. Sub-threshold cohorts are suppressed, including against differencing attacks that subtract two legitimate queries.
A two-field lane boundary
The security lane holds raw signals under its own short TTL. Its interface to the operational lane carries exactly two fields, a bot label and a confidence score, and is closed to additions.
No returning-visitor capability
No route matches /visitor, /subject, /returning, /identity or /lookup, and the query builder has no code path that can produce a WHERE token = clause.
Bring your DPO to the demo.
Thirty minutes: the aggregate-only dashboard against a traffic profile like yours, the lane architecture, and the evidence pack your reviewers will ask for.