Most analytics work goes sideways at a very specific point: a feature ships, someone opens the dashboard three weeks later, and the numbers don't line up with what anyone expected. Then the debugging starts. Was the event never fired? Fired twice? Named checkoutcomplete in one place and purchasesuccess in another? Nobody knows, because nobody wrote it down as a requirement in the first place.
The fix isn't more analytics tooling. It's treating events like any other requirement — with a template, acceptance criteria, and a trace link that goes from "the PM asked for this" all the way to "here's the tile on the dashboard and the test that proves it fires." That's what an analytics requirements event model actually is: a contract, not a wish.
This post walks through concrete templates, naming rules, and trace links you can copy directly. No theory. The examples are the point.
Where analytics quietly falls apart
The failure almost never looks dramatic. Here's the usual sequence:
A PM writes a ticket: "Add analytics to the new onboarding flow." Engineering interprets that as "fire an event when onboarding starts and finishes." Nobody specifies properties, so the event ships with no stepname, no plantype, no way to segment. Two sprints later the growth team asks "what's the drop-off between step 2 and step 3?" — and the answer is that the data doesn't exist. Technically instrumented. Just useless.
What tends to happen across a lot of teams is that analytics requirements live in three places at once and agree in none of them: the PRD says one thing, the tracking plan spreadsheet says another, and the actual code fires a third. No single source means no way to catch drift.
The root cause is that analytics gets treated as a side effect of a feature rather than a deliverable with its own acceptance criteria. This is the same pattern that makes non-functional requirements fail — they're implied, not specified, and implied requirements don't get tested. If you've read our take on why NFRs fail in delivery, the mechanism is identical: no spec, no trace, no monitor, no chance.
The event-model template (copy this)
Every trackable event should have a written record before a line of instrumentation code is merged. Not a novel — a compact, structured entry. Here's the template that works without becoming bureaucratic overhead:
Stop losing track of critical project requirements.
GoReqly helps you capture, organize, and track every requirement with precision and clarity.
- Centralized requirements repository
- Collaborative editing & commenting
- Traceability & version control
No credit card required
| Field | Example | Why it matters |
|---|---|---|
| Event name | onboardingstepcompleted | The canonical name. Nothing else fires under a different name. |
| Trigger | User clicks "Continue" and validation passes on any onboarding step | Removes ambiguity about when it fires |
| Fires when NOT | Validation fails; user navigates back | Prevents double-counting and phantom events |
| Properties | stepnumber (int), stepname (string), plantype (enum), timeonstepms (int) | Defines the shape so dashboards can segment |
| Owner | Growth PM | One name, not a team |
| Linked requirement | REQ-412 (onboarding funnel) | The trace link upstream |
| Linked dashboard tile | "Onboarding Funnel" → step conversion | The trace link downstream |
| Acceptance test | testonboardingstepeventfires | Proof it works |
The two rows people skip are "Fires when NOT" and the acceptance test. Those are also the two that save you. The "fires when NOT" row is where you catch the double-fire before it ships. The test row turns the whole thing from documentation into something enforceable.
Worth stating plainly: if an event doesn't have a linked dashboard tile or a defined downstream use, you probably shouldn't be building it yet. Vanity events — instrumented "just in case" — are where tracking plans rot. A typical mid-size product tracking plan has 200+ events and maybe 40 that anyone actually looks at.
Naming conventions that don't fall apart at scale
Naming feels like the trivial part. It's the part that quietly wrecks analytics six months in, because two engineers on two teams will name the same concept differently if you let them.
``object_action``
-
object= the thing (cart, onboarding, invoice, subscription) -
action= what happened, past tense (viewed, completed, failed, submitted)
So: cartviewed, invoicedownloaded, subscriptioncancelled. Not ViewedCart, not userdownloads_invoice, not CancelSub.
A few hard rules that prevent the most common messes:
-
Past tense for actions, always. Events describe things that already happened.
paymentsucceeded, notpaymentsuccessorsucceed_payment. -
snakecase everywhere. Mixing
camelCaseandsnakecaseacross a warehouse is a genuine source of broken joins. -
No product-name prefixes.
checkoutv2completedbecomes a lie the day v2 is the only checkout. Version in a property, not the name. -
Properties over event proliferation. Don't create
signupfreeandsignuppro. Createsignup_completedwith aplanproperty. Ten variations of the same event is a query nightmare.
The pattern nobody enforces but should: the event name is the only thing that can't be fixed cheaply later. Properties you can add. Bad property values you can clean up in the warehouse. But a wrong or inconsistent event name, once it's in a year of historical data, is permanent. Spend your rigor there.
Instrumentation acceptance criteria — the part QA can actually run
An analytics requirement that can't be tested is a suggestion. The whole point of framing events as requirements is that acceptance criteria become executable, the same way feature acceptance criteria should. We've written before about how loose criteria break QA and how to make them test-case-ready — analytics is the sharpest example of this, because the "did it work?" question is binary and automatable.
Good instrumentation acceptance criteria read like this:
-
GIVEN a user on step 2 of onboarding with a
proplan selected -
WHEN they click Continue and validation passes
-
THEN exactly one
onboardingstepcompletedevent fires withstepnumber=2,stepname="accountdetails",plantype="pro", and a non-nulltimeonstep_ms
Three things make that testable that most analytics tickets miss:
-
"Exactly one" — this catches the double-fire, the single most common analytics bug.
-
Named property values, not just property names.
plan_type="pro", not "include plan type." -
Null-checks on numeric properties —
timeonstep_msbeingnullor0because the timer never started is a classic silent failure.
The practical enforcement: use whatever your stack supports to assert events in an integration or E2E test. Many analytics SDKs let you spy on the outgoing payload. If yours doesn't, a network intercept in Cypress or Playwright works. The test doesn't need to be fancy. It needs to fail when the event breaks.
A quick checklist before any event ships
-
- [ ] Event has a canonical name following
object_action -
- [ ] "Fires when NOT" cases are written down
-
- [ ] Every property has a type and, where relevant, an enum of allowed values
-
- [ ] There's a named owner
-
- [ ] It links upstream to a requirement
-
- [ ] It links downstream to a dashboard tile or defined use
-
- [ ] An automated test asserts it fires exactly once with correct properties
-
- [ ] The name is checked against the existing tracking plan for collisions
If an event can't tick all eight, it's not ready — it's a draft.
The trace link: requirement → event → dashboard → test
This is the part that turns a tracking plan from a spreadsheet into a system. Each event carries four IDs that let anyone walk the chain in either direction.
The workflow, in plain terms:
-
A requirement gets an ID — say REQ-412
"Measure onboarding funnel drop-off."
-
That requirement spawns one or more event specs, each with its own ID and the template above. REQ-412 →
EVT-88(onboardingstepcompleted). -
Each event spec names the dashboard tile it feeds.
EVT-88→ DASH-Onboarding-Funnel, tile: step conversion. -
Each event spec names its acceptance test.
EVT-88→testonboardingstep_completed.
The chain works both ways. When the funnel dashboard shows a weird number, you start at the tile, trace back to EVT-88, read exactly when it's supposed to fire, and check the test. When someone changes the onboarding flow, you start at REQ-412, see every event it touches, and know which dashboards and tests to update before the change ships.
The failure this kills: the orphan dashboard. Every company has dashboards showing numbers nobody can explain, fed by events nobody remembers building, tied to no requirement. When the number looks wrong, there's no way to tell if the data is wrong or the dashboard is wrong. Trace links make that question answerable in a few minutes instead of a few days.
A simple diagram of the trace link helps explain the flow.
The failure this kills: the orphan dashboard. Every company has dashboards showing numbers nobody can explain, fed by events nobody remembers building, tied to no requirement. When the number looks wrong, there's no way to tell if the data is wrong or the dashboard is wrong. Trace links make that question answerable in a few minutes instead of a few days.
A real scenario
A small B2B SaaS team — project management tool, around 30 people — kept getting burned by their activation dashboard. It showed activation hovering around 22%, and leadership had built a quarterly goal around moving it. The problem: nobody could agree on whether 22% was real. The "activated" event had been renamed once during a refactor, fired twice on a specific browser path, and the dashboard was silently mixing two definitions of activation from before and after a redesign.
They spent about three weeks reconstructing what the number actually meant. When they finally traced it, roughly 15% of "activation" events were double-fires, and the true rate was closer to 26% — a meaningfully different story that had been driving the wrong roadmap decisions for two quarters.
After that, they moved to event specs with trace links. The change wasn't dramatic in effort — maybe an extra 20 to 30 minutes per feature to write the event spec and wire up a test. But the payoff was concrete: the next time an engineer refactored a flow, the linked test failed in CI before merge, flagging that activation_completed had stopped firing. The bug never reached the dashboard. That single catch saved another multi-week "what does this number mean" investigation.
The honest part of this story: they didn't retrofit every legacy event. They tagged the top 40 or so events that fed real decisions and left the rest. Trying to fix all 200 would have stalled out. Fixing the ones that mattered took about a sprint.
When this is worth it — and when it isn't
This makes sense when:
-
Analytics drives real decisions — pricing, roadmap, funnel work
-
More than a couple of people are touching instrumentation
-
You've already been burned by a number nobody could trust
-
Events are shared across teams, where naming drift is guaranteed
This is overkill when:
-
You're pre-product-market-fit and instrumenting exploratory events you'll throw away
-
A single person owns all analytics and holds the whole model in their head
-
You're tracking fewer than a dozen events total
Who should NOT do this: teams that will write the specs and then never enforce the tests. A tracking plan that isn't tied to CI is just documentation, and documentation drifts from reality the moment it's written. If you can't wire the acceptance test into your pipeline, start there before building out the full model — an untested event spec buys you very little.
The one habit that holds it together
no event ships without a test that asserts it fires exactly once with the right properties. Everything else — the naming rules, the templates, the trace IDs — is scaffolding around that one enforcement point. The naming keeps the data queryable, the trace links keep it explainable, but the test is what keeps it true over time.
Analytics rots quietly. A feature refactor six months from now will break an event, and without a failing test, nobody notices until leadership is staring at a dashboard trying to figure out why activation dropped 8 points overnight. Wire the event to a requirement, wire the requirement to a test, and that whole class of expensive, slow, trust-destroying investigation just stops happening.
Analytics rots quietly. A feature refactor six months from now will break an event, and without a failing test, nobody notices until leadership is staring at a dashboard trying to figure out why activation dropped 8 points overnight. Wire the event to a requirement, wire the requirement to a test, and that whole class of expensive, slow, trust-destroying investigation just stops happening.
Ready to transform your product delivery?
Join 2,000+ teams using GoReqly to improve requirements accuracy, reduce rework, and accelerate time to market.