Architecture

Four moving parts,
one trust boundary.

Everything runs on machines you control. The collector is the only internet-facing component; ClickHouse and the API sit behind it. One boundary, one place where the outside world meets your deployment.

The flow

Beacons in, honest numbers out.

Your sitesone-line snippet · async · first-party subdomain · domain-locked
beacons
Collector :8090zero-dep Node · origin allowlist · PII scrubbing · daily HMAC identity · raw IP never marshaled · disk-spool replay · event-id dedup · rate limits · payload caps
validated batches
ClickHouse :8124events TTL 24 h · materialized rollups 25 mo · TDigest percentiles · heatmap grids
API + dashboard :8081PBKDF2 auth · RBAC · k-anonymity post-filter · audit log · /api/v1 · share snapshots
scoped keys
MCP (stdio)15 tools for Claude / Cursor / Claude Code — gated by key scopes + site allowlists
Slack / webhooks
Alerts + digestevaluated every minute from rollups · cooldowns · weekly digest

The recorder path (session replay, Tier 2) enters through the same collector and stays inside the same boundary: chunks upload to the collector, store for 30 days, and inputs are masked at source — values never leave the browser.

Why it holds

The boundary is enforced, not promised.

Ed25519-signed site configs

The collector accepts only signed configs for allowlisted domains. An unsigned snippet, or the same code pasted on any other site, is refused at the edge with a 403.

Postgres when you grow

The control plane is JSON files today, with a Postgres adapter behind the same interface. Scaling the control plane is a config swap — not a migration project.

Zero supply chain

Collector, API, SDK, dashboard and MCP server carry no npm packages. The serving path is code you can read end to end — on your own hardware.

Identity, precisely

Derived server-side, rotated daily.

Identity is an anonymized device-day pseudonym: a daily-rotated HMAC-SHA256 (HKDF key, midnight UTC) over what the browser already sends, namespaced per site. Yesterday's hash cannot be joined to today's; your sites cannot join each other's visitors. The raw IP lives for milliseconds in collector memory — used for geo and the daily HMAC input — and is never persisted, marshaled or logged.

One boundary.
Your machines behind it.

Four components, one internet-facing listener, zero third-party endpoints. Deployed with your DevOps, verified at deploy time, boring ever after.