Skip to main content
Pre-launch analytics spec: pasteable event lists, funnel wiring and QA sign-offs for PMs

Pre-launch analytics spec: pasteable event lists, funnel wiring and QA sign-offs for PMs

The thing everyone skips until the dashboard shows nothing

Launch day goes fine. Feature ships, no errors, support queue is quiet. Then three days later someone in the leadership channel asks, "So what's the activation rate on the new flow?" and you open the dashboard and it's just... empty. Or worse, it's full of numbers that are obviously wrong — a signup funnel showing more purchases than page views, a step that fires twice for half your users, an event named btnclick2_final that nobody can decode.

At that point you're not analyzing a launch. You're doing forensic archaeology on your own tracking, two weeks after the data you actually needed is already gone.

The fix isn't more analytics tooling. Most teams already have Amplitude or Mixpanel or GA4 wired up. The real fix is treating the pre-launch analytics spec as an actual deliverable — something that ships before code, gets reviewed like code, and gives engineers something unambiguous to implement. What follows is the structure of that spec, with pasteable pieces you can lift directly.

Why tracking rots before launch (and it's not laziness)

The usual story is that engineers "forgot" to add tracking. That's almost never what actually happened.

What happens is more like this: the PM writes a ticket that says "add analytics for the new onboarding flow." An engineer, mid-sprint, interprets that however makes sense to them at 4pm. They name events based on the component they're editing, not the user action. They fire the event where it was convenient in the code, not where the user actually did the thing. Nobody defined properties, so properties get invented on the spot or skipped entirely. QA tests that the feature works — not that the events fire correctly, because there was never a test case for events.

Every one of those decisions is locally reasonable. The result is globally useless.

The second failure mode is ownership drift. A signup event lives in the frontend repo, but the "signup completed" server confirmation lives in the backend. Two people, two firing points, zero agreement on which one is the source of truth. You end up double-counting, or more often, silently missing the server-confirmed version and reporting the optimistic frontend number — the one that includes people who bounced on a validation error.

Neither of these is a tooling problem. They're spec problems. The spec was vague or didn't exist, so everyone filled the gap with a guess.

What a pasteable event list actually looks like

The core artifact is a table an engineer can read once and implement without asking you anything. Vague specs generate Slack threads; precise specs generate commits.

Here's the format that holds up. Each row is one event, and every column exists because leaving it out has burned someone before.

Event nameTrigger (exact moment)Fires whereRequired propertiesOwnerDedup key
onboarding_startedUser lands on step 1, first renderCliententrysource, plantier, is_invitedWebsession_id
onboardingstepcompleted"Next" clicked AND validation passesClientstepnumber, stepname, timeonstep_msWebsessionid + stepnumber
account_createdServer confirms row writtenServeruserid, plantier, signup_methodBackenduser_id
firstvalueactionUser completes their first real taskClientactiontype, userid, mssincesignupWebuser_id
  1. "Trigger" describes the user moment, not the code. "Next clicked AND validation passes" is unambiguous. "On button click" is not — it doesn't tell the engineer whether to fire before or after the request resolves, which is exactly where double-counting is born.
  2. "Fires where" forces the client-vs-server decision up front. The rule of thumb worth writing down: anything that must be trustworthy for revenue or activation reporting fires server-side. account_created on the client will always over-report because it fires for people who never actually got a row in the database.
  3. The dedup key is the column nobody adds until after their first messy launch. It tells the engineer — and future you — what makes an event unique so you can catch duplicates. onboardingstepcompleted keyed on sessionid + stepnumber means a user completing step 2 twice shows up as a bug instead of hiding as inflated throughput.

Property naming deserves one hard rule: pick snake_case or camelCase, write it at the top of the spec, and never negotiate it again per-event. Mixed casing across events is the single most common reason a "simple" dashboard query turns into a 40-minute string-matching exercise.

State the property naming convention at the top of the spec so implementers don't invent casing on the fly.

Every column exists because leaving it out has burned someone before.

Wiring the funnel before the events exist

Most teams build the event list, ship it, then try to assemble a funnel from whatever came back. That's backwards. Define the funnel first, because the funnel tells you which events you actually need — and which ones you don't.

A funnel definition is four things written plainly:

  1. The ordered steps, named as events that exist in your list.
  2. The conversion window — how long a user has to move from step one to the last step before they're counted as dropped. This is a decision, not a default. A 30-day trial funnel and a 90-second checkout funnel cannot share a window.
  3. The denominator — who enters the funnel. "All users who hit onboarding_started" is very different from "all users who created an account." State it once so nobody quietly redefines it in a dashboard filter.
  4. The segments you'll always slice by — usually plantier, entrysource, platform. If a segment matters for the launch decision, its property has to be on every step's events, not just the first one. This is the sneaky requirement that breaks funnels: you can't segment step 4 by plantier if plantier only lives on step 1.

> Funnel: Onboarding activation > Steps: onboardingstarted → onboardingstepcompleted (step 3) → accountcreated → firstvalueaction > Window: 7 days from onboardingstarted > Denominator: all onboardingstarted events > Required segment properties on every step: plantier, entrysource

Writing this before code means you catch the gap now — "wait, firstvalueaction doesn't carry plan_tier" — while it's a one-line edit to the spec instead of a re-instrumentation ticket after launch.

If you're shipping the feature partly to test a hypothesis, the funnel is your measurement. It's worth borrowing the discipline from validating roadmap bets with lightweight experiments — define the decision rule before the data arrives, so you're not rationalizing whatever the numbers happen to show.

Ownership rules that stop the finger-pointing

The moment two teams touch the same feature, tracking ownership gets murky. Murky ownership is how events silently break during unrelated refactors. Someone renames a component six weeks later, the event goes with it, and nobody notices because nobody actually owned it.

  1. Every event has exactly one owning team, written in the spec. Not "web and backend" — one. The owner is responsible for the event firing correctly, including after refactors they didn't plan.
  2. The event's owner is the team that owns the firing point, not the team that requested the data. If the PM needs account_created but it fires server-side, backend owns it. This prevents the classic mess where the requester assumes it's handled and the implementer assumes it's optional.
  3. Cross-team events get a named DRI, not a shared responsibility. Shared responsibility for tracking is the same as no responsibility. When onboarding spans two repos, one person signs off that the whole funnel fires end-to-end.

Cross-team launches are where analytics quietly fall apart even when everything else goes right. The coordination discipline from a broader cross-team launch orchestration playbook applies directly here: someone has to own the seam between teams, or the seam is where things break.

The QA sign-off nobody writes (until they've been burned)

Feature QA and analytics QA are different jobs. Feature QA asks "does the button work?" Analytics QA asks "when I click the button, does exactly one correctly-named event fire, with all required properties, with the right values?" Almost every team does the first and skips the second, then discovers the gap when the dashboard is already lying to them.

  1. Each event fires exactly once for its trigger action (watch for double-fires on re-renders)
  2. No event fires on page load that should require user action
  3. Every required property is present and not null / not undefined
  4. Property values are correct — plantier shows pro, not the literal string plantier
  5. Server events don't fire on validation failures or aborted requests
  6. Event names in the live stream match the spec character for character
  7. The full funnel completes end-to-end for one test user, in order
  8. Segment properties appear on every step, not just the first
  9. No orphan events firing that aren't in the spec
  10. Casing is consistent with the spec convention

The single highest-value line is the "exactly once" check. Double-firing is invisible in feature testing and catastrophic in reporting — it inflates every rate that uses that event and it's nearly impossible to correct retroactively, because you can't tell which of the two fires was "real."

Make this sign-off a launch gate with a name attached. "Analytics QA: signed off by ___" belongs on the launch checklist next to "no P0 bugs." If it's optional, it will be skipped under deadline pressure every single time.

A real scenario: the funnel that reported backwards

A small B2B SaaS team — maybe a dozen people, one PM — shipped a redesigned trial signup. Feature worked flawlessly on launch. Two weeks in, the activation funnel showed something impossible: more trialactivated events than trialstarted events. Activation rate over 100%.

Two separate mistakes had stacked. trialstarted fired server-side only on a fully valid signup, so it under-counted — anyone who hit a validation error never triggered it. trialactivated, meanwhile, fired client-side on a component that re-mounted whenever the user navigated back to the dashboard, so it over-counted — sometimes three or four times per user.

Nobody caught it before launch because there was no analytics QA step. Feature QA passed because the trial genuinely worked. It took a week and a half to sort out — re-instrument both events, backfill nothing (that data was gone), re-validate — before anyone trusted the numbers again. The launch retro couldn't answer "did activation improve?" because the two most important weeks of data were unusable.

The fix afterward wasn't complicated. A one-page spec with the event table, a defined funnel with a 14-day window, and a five-minute analytics QA pass in the live event stream before the gate. The next launch produced a funnel that was believable on day one. Not perfect — one property was missing a value in edge cases — but believable, and correctable in hours instead of never.

When a full spec is overkill

Not every change needs this. If you're tweaking copy, adjusting a layout, or shipping something with zero new user actions worth measuring, writing a formal analytics spec is ceremony for its own sake.

The rule that keeps it honest: you need a spec when the launch will be judged by a metric you can't currently produce. If leadership is going to ask "did it work?" and the answer requires new events or a new funnel, spec it. If nobody will look at a number for this change, skip it.

Where teams get it wrong is the middle ground — a "small" feature that turns out to be the whole point of the quarter. If there's any real decision riding on the outcome, treat it as spec-required. The cost of a missing spec isn't the writing time. It's the irreplaceable launch-window data you only realize you needed after it's already gone.

Bringing it together

The whole point of a pre-launch analytics spec is to move every ambiguous decision — event names, firing points, ownership, what counts as a step — from "figured out in the moment by whoever's touching the code" to "written down and reviewed before anyone writes the code." Engineers implement it without guessing. QA has something concrete to verify against. When the leadership question lands three days post-launch, the dashboard already has the answer.

None of the pieces are hard on their own. The event table takes maybe an hour. The funnel definition takes fifteen minutes. The QA checklist takes five minutes to run.

Here's a simple workflow diagram to visualize the spec, funnel, ownership, and QA steps before launch.

Process diagram

What's hard is doing them before launch, when everything is competing for attention and tracking feels like the thing you can always fix later. You can't always fix it later. The data from the days you didn't measure is simply gone — and that's the one thing no tooling ever gets back for you.

None of the pieces are hard on their own. The event table takes maybe an hour. The funnel definition takes fifteen minutes. The QA checklist takes five minutes to run. What's hard is doing them before launch, when everything is competing for attention and tracking feels like the thing you can always fix later. You can't always fix it later. The data from the days you didn't measure is simply gone — and that's the one thing no tooling ever gets back for you.

Built for Product Teams Designed specifically for product managers and agile workflows
Save Time Streamline roadmapping, prioritization & release planning
Increase Transparency Keep stakeholders informed with real-time updates
Drive Growth Focus on impact-driven features and customer value