Skip to content
← All resources

Developers

How collection and analysis actually work

The parts a developer wants to know before putting anything in front of production traffic: what is on the request path, what is written where, what the event contracts look like, and what stops a language model inventing a number.

Nothing analytics does is on the request path

The invariant everything else is built around: no analytics call, database read or control-plane lookup happens while a visitor is waiting. The edge emits a record to a local durable spool and answers the request; a regional collector drains the spool, streams to the processing pipeline and lands in the analytical store afterwards.

That ordering is what makes an analytics outage boring. If the pipeline stops, the spool grows and the site is unaffected — which is the only acceptable failure mode for something sitting near production traffic.

The collection path

Five hops, none of which the visitor waits for.

Envoy request / access data
        ↓
local analytics emitter          (in-process, non-blocking)
        ↓
durable local spool / journal    (survives a restart)
        ↓
regional collector → Kafka / Redpanda
        ↓
stream enrichment → ClickHouse

The edge event, and what it deliberately omits

A dedicated analytics event family, not a reused security event. Security decisions and web analytics have different shapes and different retention, and conflating them costs both.

  • Recorded: site, timestamp, edge region, normalised path, route template, method, status, content type, referrer source and host, campaign parameters, country, device class, browser and OS family, traffic type, crawler family, security disposition, origin and edge latency, response bytes, release ID
  • Never persisted by default: raw auth headers, request bodies, cookies, arbitrary headers, full raw IP, unrecognised query strings
  • Campaign parameters come from an allowlist — utm_source, utm_medium, utm_campaign, utm_content, utm_term, gclid, msclkid, fbclid — and everything else is discarded or redacted

Route templates

Supply templates from your application and paths normalise on ingest. This is a privacy control and a cardinality control at the same time.

/orders/883729   →  /orders/:id
/users/8273      →  /users/:id
/invite/9f2a...  →  /invite/:token   (value discarded, not hashed)

Smart Beacon

  • Served from a first-party path on your own domain — for example /__reveliqo/event — so it is a first-party network path with a simpler CSP story
  • Small bootstrap, asynchronous, non-blocking, no framework dependency
  • Events are batched and delivered with sendBeacon or fetch keepalive so a page unload does not lose them
  • Hooks for single-page navigation, and sampling controls for high-volume behavioural events
  • Browser blockers can interfere with any client-side beacon — which is why core request analytics do not depend on one

A business event

The idempotency key is not decoration. Webhooks retry, queues redeliver, and a duplicated subscription.started is a revenue figure you cannot unpick a month later.

POST /v1/events
Idempotency-Key: ord_2026_09_21_5f8a1c

{
  "event":       "subscription.started",
  "site_id":     "site_123",
  "customer_id": "cust_hash_abc",
  "occurred_at": "2026-09-21T17:45:00Z",
  "value":       149,
  "currency":    "EUR",
  "properties":  { "plan": "business", "billing_period": "monthly" }
}

Recommended event names

Use these where they fit so the packaged funnels and revenue views work without mapping. Namespace anything custom.

  • lead.created · trial.started · account.created
  • order.completed · subscription.started · subscription.upgraded
  • subscription.cancelled · refund.created · appointment.booked
  • Send the unhappy path too — a refund that never arrives leaves revenue permanently overstated

The semantic metric layer

Every metric has one canonical definition, held in a semantic layer rather than re-implemented per report. conversion_rate means one thing across the brief, the funnel, the API and the scheduled email, which is why two screens cannot quietly disagree.

The AI reaches metrics by calling approved operations against that layer. It does not write warehouse SQL, and it has no path to the store that bypasses the definitions. A model cannot invent a metric it has no way to compute.

Collected text and referrers are untrusted

Campaign names, referrer URLs and event properties arrive from the open internet. Anyone can send your site a request with a campaign name designed to read like an instruction.

  • Collected text is data inside a context packet, never system or tool instruction
  • The model's tool surface is the approved metric and dimension set, so there is no arbitrary query it could be persuaded to write
  • Authorisation is checked before context assembly — the assistant cannot receive data the asking user could not open themselves

Storage

  • ClickHouse for normalised analytical events, time series, funnels and journey aggregations
  • PostgreSQL for accounts, sites, goals, integration configuration, metric definitions and scheduled reports
  • Object storage for cold archives and exports
  • Kafka or Redpanda between the collectors and processing
  • Materialised daily and hourly aggregates, so an ordinary management question never triggers a raw-event scan

Keep reading

The rest of the documentation

Connect a site today. Read tomorrow's brief instead of building it.

Connect a site and the first brief arrives with the day's changes already explained — traffic separated from bots, conversions attached to revenue, and the evidence behind every sentence one click away.

Real people separated from bots Every answer shows its evidence Reveliqo runs on Reveliqo