Analytics pipelines you can actually trust
There's a phase every data setup reaches, usually around month nine, where half the company stops looking at the dashboards. Not because they don't care — because someone caught a chart lying. Signups double-counted by a retry. A funnel step that never fires on Safari. Revenue that doesn't reconcile with billing, off by 4%, definitively unexplained. Trust in analytics is binary and non-renewable: once a room watches a chart be wrong, every chart in that room is wrong forever.
The uncomfortable truth is that most analytics pipelines are built like prototypes and operated like infrastructure. The event you fired in a commit at 11pm becomes somebody's board metric. This piece is how we build the boring version — the one where numbers mean things — on our engineering engagements: schemas, validation at the edge, QA environments for data, and the unglamorous pruning that keeps the whole thing legible.
Events are an API — version them like one
The foundational failure of most analytics stacks is treating events as log lines: stringly-typed, fire-and-forget, named by whoever shipped the feature. But every event is a contract — between the product that emits it and every dashboard, experiment, and alert downstream. Contracts need schemas.
The working setup:
One schema registry, in the repo. Every event declared with a name, a typed payload, an owner, and a description written for the person reading the dashboard, not the person writing the code. checkout_completed has a total_cents: integer and a currency: ISO-4217 — not "amount (probably dollars?)". We generate the tracking types from this registry so the tracking call sites are compile-checked; you cannot fire an event the schema doesn't know about. This is the same discipline as one schema everywhere, applied to the pipeline most teams forget has consumers.
Naming is taxonomy, not taste. object_action past tense — report_downloaded, not downloadReport or dl_report_v2. The taxonomy comes before the tooling (name your events before you buy the analytics tool makes the full case from the growth side), and renames are breaking changes that go through the same deprecation path as any API: alias, migrate, remove. The teams that skip this end up with signup, user_signup, Sign Up, and sign_up_complete all in production at once, and a growth analyst doing join therapy in SQL forever.
Properties obey a small constitution. snake_case everywhere. IDs are strings. Money is integer minor units with currency. Timestamps are UTC ISO-8601 with a defined clock source (server clock wherever possible — client clocks lie in ways that quietly corrupt time-to-event analyses). Boring constitutions prevent interesting bugs.
Validate at the edge, quarantine what's broken
A schema that lives in a document is a wish. Validation has to run where events enter the pipeline — the collector endpoint or the first ingestion stage — and it has to have a failure policy, which is the part nobody designs:
Reject loudly in development. Client-side validation in dev and staging surfaces schema violations in the console and CI on the day the event is written. The developer who names a property userID instead of user_id finds out before merge, not in next quarter's dashboard archaeology.
Quarantine in production, never drop silently. Events that fail validation in prod go to a dead-letter stream with the failure reason attached, and the quarantine volume is a monitored metric. Silent dropping is the worst option — it converts engineering mistakes into unfalsifiable business numbers. Loud rejection is fine internally but too lossy for third-party-client realities. Quarantine gives you the third thing: bad events are visible, debuggable, recoverable, and above all counted.
This connects directly to frontend observability thinking: the health of the measurement system is itself something you measure.
A QA environment for data, not just code
Nobody would deploy an untested payment flow, yet teams routinely ship untested measurement of that payment flow and make board-level decisions on the output. We treat each release's instrumentation as testable:
Event coverage in CI. Critical-path flows — signup, activation, purchase — have Playwright tests that assert the expected event sequence fired with valid payloads, alongside asserting the UI worked. The taxonomy piece (analytics governance) covers the planning side; this is the enforcement side. When someone renames a funnel step or drops a property, a test fails the same way it would if they'd broken the button.
A staging analytics destination. Staging environments send real events to a sandbox project in the same tool, and before any measurement-sensitive release, a human walks the critical flows in staging and watches the events arrive — named right, sequenced right, payloaded right. Fifteen minutes. It catches the entire category of "the event fires before the property exists" bugs that staging-less teams find in production data two sprints later.
Reconciliation checks against systems of record. The pipeline's numbers continuously reconcile against sources that can't be wrong in the same way: signups against the auth database, revenue against billing, and (increasingly) AI-feature usage against inference logs (see analytics for AI features). Automated, scheduled, alerting on drift beyond a threshold. The 4% gap from the intro is always there; the question is whether you find it in a reconciliation alert or in a board meeting.
Privacy shapes the pipeline; it isn't a consent banner afterthought
What you can collect defines the schema more than what you'd like to collect. Regional consent regimes, the death of third-party cookies, and plain decency mean the pipeline should be designed around a principle of minimal surprise: collect events about product behaviour, tie them to pseudonymous IDs, keep the retention window stated and honoured, and design analyses that work with the data a respectful pipeline yields. A tracking plan written with a privacy lens from the start also survives procurement reviews in a way a bolted-on consent mode never does — procurement can tell. Attribution modelling that admits its own uncertainty (attribution that admits what it doesn't know) is the honest analytics culture's other half: precision within the pipeline, humility about what it proves.
Prune like a gardener: kill metrics nobody reads
The unglamorous discipline that keeps the whole system legible: metrics and events have owners and sunsets, and unused ones get deleted.
Every quarter, review the inventory. Any dashboard unviewed for two quarters (tools tell you this; ask for the feature), any event unqueried in three, any property nobody's ever filtered on — goes on a kill list with its owner tagged. Owners can defend their metric in one line ("we check it during launches") and it stays; silence deletes. What survives the cull is a measurement surface a new analyst can actually learn, and an event volume your tooling bill doesn't groan under.
The harder cultural piece: deprecated events get tombstones, not ghosts. When you kill or rename an event, the schema registry keeps the tombstone — name, lifespan, reason, successor. Next year's analyst, staring at a time series that stops dead in March, deserves to know whether the business ended or the instrumentation did. This one habit prevents a startling amount of executive panic.
What we ship by default
- Schema registry in-repo, codegen'd tracking types, written for dashboard readers.
- Naming constitution; renames treated as breaking changes with migration paths.
- Edge validation: loud in dev, quarantined-and-counted in prod.
- Event-sequence tests on critical flows; a staging destination walked before releases.
- Automated reconciliation against systems of record, with drift alerts.
- Quarterly metric review with owners-and-sunsets; tombstones for everything killed.
Key takeaways
- Analytics trust is binary and non-renewable; one visibly wrong chart poisons all of them. Build for correctness, not coverage.
- Events are an API: schema registry in the repo, typed codegen'd tracking, owners and descriptions, renames as breaking changes.
- Validate at ingestion with a designed failure policy — silent drops convert bugs into business numbers.
- Instrumentation is testable: event-sequence assertions in CI, a staging destination, and continuous reconciliation against systems of record.
- Design the pipeline around privacy from the start; consent bolted on later is visible to everyone who inspects it.
- Metrics have owners and sunsets. Kill what nobody reads, and tombstone everything you kill.
FAQ
Isn't a full schema registry overkill for a small product? The registry scales with you — ten events in a typed file is still a registry, and it costs an afternoon. What's overkill is rebuilding trust in your data at forty people because the taxonomy was vibes at five. Small now is exactly when the discipline is cheap.
Which tool should we use for the pipeline? The honest answer is that the tool matters less than the contract. A clean schema with validation survives migrating between vendors; a typed event layer that generates its payloads from the registry makes the vendor a detail. Pick based on your query patterns and budget, not your schema.
How do we measure the pipeline's own health? Three numbers: validation-quarantine rate (should sit near zero and alert on spikes), reconciliation drift versus systems of record (bounded, trending down), and event-to-dashboard lag. If you can only watch one, watch reconciliation — it's the one that catches lying.
What do we do about historical data that's already untrustworthy? Mark it. A clearly labelled "pre-registry" line, visible in every long-range chart, is infinitely better than silently mixing eras. Back-filling corrected history is occasionally feasible but usually archaeology; honest discontinuity is the professional answer.
Who should own analytics engineering — data or product engineering? Whoever writes the tracking calls owns their correctness, which means product engineering owns emission and the schema registry is theirs to maintain. Data/analytics owns consumption and reconciliation. Blurry ownership is how events get named dl_report_v2 in the first place.
Dependency hygiene: the boring audit that saves the launch
Client codebases rot at the package.json line. Audit cadences, update windows, vendoring decisions, and the licence review nobody does until procurement asks.
Name your events before you buy the analytics tool
Event naming decides whether your data answers questions in year three. The taxonomy anatomy we design before any tool evaluation: verbs, properties, screens, migration.
Engineering the 80-millisecond moments
Micro-interactions are where product quality is felt. Press states, instant visual feedback, focus continuity, and testing feel with the same rigour as function.