How it works
From a click to a row an agent can read
Each stage runs the same privacy rules again instead of trusting the stage before it. The client is not a trust boundary.
- Step 1
Middleware mints a journey token
middleware.ts issues a signed, per-site token and forwards it as a request header on the same request, so the very first collect call is authorized.
- Step 2
The client watches four things
Route changes become page_view events. Three clicks within 1 second and 30 px (four taps and 44 px on touch) become one rage_click. A click with no DOM effect within 700 ms becomes a dead_click.
- Step 3
Events queue and batch
Events wait in an IndexedDB queue and leave in batches. A session stops at 200 events and marks itself truncated.
- Step 4
The collector re-checks everything
It verifies the token, derives the site id from it, strips query strings and hash fragments again, re-scrubs click labels, rate-limits on a daily-salted IP hash and flags known bot user agents as synthetic.
- Step 5
Workers summarize and expire
session-close writes one session_summary per session after 30 idle minutes; daily-rollup aggregates per route and day with prior-period baselines; retention drops raw-event partitions older than 14 days.
- Step 6
Agents query three endpoints
Sessions, rollup and compare. Every response states its absolute time window and the rule versions that produced it.
How a session ends
The worker classifies every closed session with exactly three rules, in this order.
- converted
- The session has any conversion event
- bounce
- One page view and no rage or dead click
- engaged
- Everything else
Wire it into your app
Middleware, a collect route, storage and the client.