Analytics Plumbing: Event Tracking That Survives the First Product Iteration
The cruelest part of SaaS analytics is that broken analytics is worse than no analytics. No analytics means you know you're flying blind. Broken analytics means you think you can see, and then you make decisions based on numbers that turn out to be wrong — and you don't find out until quarters later.
Here's a pattern: a product team instruments "user activated" as an event. They fire it when the user completes onboarding. Then the team refactors the onboarding flow, the event fires in a different place, and the meaning of "user activated" quietly changes. Six months later, the team looks at the retention chart and sees that activation is way up. They celebrate. Then somebody realizes the event was refactored and the numbers aren't comparable across the refactor boundary. Now nobody trusts the chart, the six months of decisions it informed are suspect, and the team has to start over.
This post is about how to avoid that. It's in the Technical Foundation cluster. Analytics plumbing is foundational for everything from activation milestones to Voice of Customer to lifecycle automation — all of those other systems run on top of this one.
The shape of broken analytics
Broken analytics comes in four characteristic shapes.
Shape 1: Events that mean different things in different places
Like the example above — the same event name fires in multiple places, sometimes for slightly different reasons. A refactor, a new feature, a bug fix — each changes the event's meaning slightly. Over time, the drift compounds until nobody can trust the metric.
Shape 2: Events that are fired but never used
The product team instruments dozens of events because "we might need it later." Nobody ever queries them. Engineering maintains the instrumentation forever. New engineers see the instrumentation and think it's load-bearing. The codebase becomes a graveyard of vestigial analytics.
Shape 3: Events that are missing for the things that matter
The team has no event for "user experienced the thing the product promises." They have events for every click, but no event that represents first value. When somebody asks "how many users reach activation," the answer is a hand-waved approximation built from proxy events.
Shape 4: Properties that are inconsistent across events
One event logs user_id as a string. Another logs it as userId. A third logs user as an object with nested fields. The analysis team spends half its time normalizing property names before they can ask any cross-event questions.
All four shapes trace back to the same underlying problem: the team never designed an event taxonomy, they just let it emerge. The fix is to design it up-front, document it, and enforce it.
Event taxonomy design
A good event taxonomy has three layers: naming, properties, and a semantic meaning doc.
Naming convention
Pick a naming pattern and use it everywhere. Two popular ones:
Pattern A: Noun Verbed (past tense, title case)
User Signed UpDashboard LoadedIntegration ConnectedReport Generated
Pattern B: noun_verb (snake case)
user_signed_updashboard_loadedintegration_connectedreport_generated
Either works. The important thing is pick one and stop debating it. Mixing conventions is the single biggest mistake — you end up with user_signup and User Signed Up and dashboard.loaded in the same system, and every query has to handle all three.
We default to "Noun Verbed" (Pattern A) because it reads more naturally in dashboards and because most analytics tools display events better in that format. Your mileage may vary.
Property taxonomy
Every event has properties. The properties should be consistent across events for the same concept. Specifically:
user_id— always the same name, always the same type (string). NeveruserId, neveruid, never nested inside auserobject.account_idortenant_id— same ruleplan— consistent values (free,pro,enterprise, notPro,professional,paid)source— where the user is coming from (web,mobile,api,email)client_timestamp— when the event happened in the user's time zone
Then events can add their own specific properties — report_type on a report event, integration_name on an integration event — but the top-level properties should be universal.
Build a tracking_plan.md or events.md in your repo that documents every event, its trigger conditions, and its property schema. Update it every time you add an event. This document is the single source of truth for what's instrumented. Without it, the taxonomy drifts immediately.
Semantic meaning
Every event needs a documented definition that answers: what does firing this event mean about the user or the product?
Bad definition: "User clicked the signup button."
Good definition: "A new user successfully completed the signup flow — their account was created in the database and they received a welcome email. This event fires exactly once per new user, server-side, after the database transaction commits. It does NOT fire on test accounts (filtered by email domain). It does NOT fire on accounts created via SSO (use 'SSO User Provisioned' instead)."
The good definition tells you exactly when the event fires, exactly what state it implies, and exactly which corner cases are excluded. When somebody later asks "how many signups did we have last quarter," the definition tells them exactly what's being counted.
The stack
For SaaS analytics, the stack typically has three layers: capture, pipeline, and analysis.
Capture
Where events are generated. The two main options:
- Client-side SDKs (browser, mobile): capture user interactions directly in the app. Pros: easy to wire up, captures UI events. Cons: can be blocked by ad blockers, slower and noisier, privacy regulations affect it.
- Server-side events: fire events from your backend after the underlying action completes. Pros: more reliable, not blocked, tied to the real database state. Cons: harder to capture pure UI interactions that don't touch the server.
The right answer is usually both. Server-side for anything that corresponds to real state changes (signup, activation, purchase, feature usage). Client-side for pure UI interactions (clicked button, viewed page, scrolled to bottom). Server-side events are the ones you trust for business metrics; client-side events are for UX research.
Pipeline
The middleware that routes events to destinations. The dominant option is Segment — a single capture API that forwards events to your analytics tools. PostHog also has a similar "one input, many outputs" model. For teams wanting to own the pipeline, custom event routing via a serverless function or a Kafka topic also works.
The pipeline layer is what lets you change analytics vendors without rewriting every event instrumentation in your app. Highly recommended, even for small teams.
Analysis
The tools where you actually query and visualize the data. The common options:
- PostHog — open source, product analytics focus, includes funnel and retention tooling
- Amplitude — enterprise product analytics
- Mixpanel — similar to Amplitude, slightly different UX
- Heap — auto-captures everything by default
- Snowflake / BigQuery + Looker / Metabase / Lightdash — for teams that want a full data warehouse
The distinction that matters: product analytics tools (PostHog, Amplitude, Mixpanel) are great for "show me funnels and cohorts on my events." Data warehouse setups (Snowflake + BI tools) are great for "join my events to customer records, pipeline data, and billing info for cross-cutting analysis."
For a growing SaaS, you probably want both eventually. Start with one. Segment sends to both, so adding the second later is trivial.
The "one dashboard per audience" rule
After the taxonomy and the stack, the remaining discipline is dashboards. This is where most analytics implementations drown: every ad-hoc question becomes a dashboard, dashboards proliferate, nobody trusts any of them.
The rule: one dashboard per audience, and no more.
Not one dashboard per person. One dashboard per audience:
- Exec dashboard: 5–8 top-level metrics (ARR, new customers, net dollar retention, activation rate, churn) — the single place leadership looks to gauge the business
- Product dashboard: funnels and retention by cohort, feature adoption, activation milestones — the single place Product looks
- CS dashboard: customer health, activation status by customer, intervention queue — the single place CS looks
- Growth dashboard: acquisition, conversion, funnel performance — the single place Marketing/Growth looks
Each dashboard has a single owner. The owner is responsible for making sure it stays accurate, meaningful, and trusted. If a metric on the dashboard is wrong, the owner fixes it. If a new metric is needed, the owner decides whether to add it.
When somebody asks a one-off question ("what was churn last week"), the answer comes from the dashboard, not from a new ad-hoc chart. If the dashboard can't answer the question, either the dashboard gets updated (if it's important) or the question gets answered one-off in a notebook (if it's not).
This discipline is annoying to enforce and it's the main reason most analytics implementations fall apart over time. The failure mode is that everybody gets permission to create dashboards, dozens pile up, three of them contain the same metric with three different numbers, and the team loses trust in the whole system.
Maintaining the tracking plan
The tracking plan is not a one-time artifact. It evolves with the product. Some ongoing discipline:
- Every PR that adds or modifies an event must update the tracking plan. Make it part of the definition of done. Reject PRs that ship event changes without doc updates.
- Run a quarterly taxonomy review. Somebody (usually PM or Analytics Engineer) reviews all events, flags unused ones for deletion, flags inconsistencies for fixing, and updates the tracking plan.
- Deprecate events explicitly. When an event is no longer fired, mark it as deprecated in the tracking plan with the date and reason. Don't just delete the code and hope.
- Monitor event volumes. If an event suddenly stops firing or starts firing 10x more often, something changed upstream. Dashboard the event volumes per day as a health check.
- Version events when meaning changes. If you need to change what an event means (different trigger conditions, new properties), create a new version (
User Signed Up v2) rather than modifying the old one in place. This preserves historical comparisons.
How to know your plumbing is working
Signs of healthy analytics:
- The question "how many customers activated last week" has one canonical answer, returned by the same query everybody runs
- The tracking plan in the repo is current (last updated within 30 days)
- Less than 5% of events are duplicate, renamed, or deprecated variants
- Dashboards get updated when the underlying metrics change, not ignored
- When somebody asks "what does this metric mean," the answer is in writing and unambiguous
- Engineers know the naming convention without having to look it up
- Less than 10% of events have no known consumer (queries, dashboards, alerts)
If most of these are false, the plumbing is broken. The cheapest fix is usually writing the tracking plan document first — the act of documentation surfaces the inconsistencies that need to be cleaned up.
Where to start
If you have no analytics today, start small:
- Install Segment (or PostHog). Wire up 1–2 events: signup and activation.
- Write the tracking plan with just those two events.
- Build the one exec dashboard and the one product dashboard.
- Add events only when they have a specific question they're going to answer.
- Resist the urge to "instrument everything." Over-instrumentation is a bigger problem than under-instrumentation for a growing team.
If you have broken analytics today, the fix is harder. The order:
- Write down what you have. Document every event, its current definition, its current trigger, its current consumers.
- Identify the drifts, the duplicates, the deprecated. Decide what to keep and what to deprecate.
- Build the tracking plan as the canonical source of truth going forward.
- Fix the drifts one at a time, with migrations documented.
- Deploy dashboard discipline — one per audience, one owner each.
This is usually a month of focused work for one engineer, possibly with a PM reviewing definitions. It's thankless but the payoff is enormous — every downstream system starts running on trustworthy data.
If the whole analytics stack is such a mess that you don't know where to start, a Growth Engine Audit will inventory the current state and give you a ranked cleanup plan.
Start with an Audit. If your data feels untrustworthy and decisions are running on gut feel even though you "have analytics," the audit will diagnose why and tell you exactly where to invest first. Book the audit call →