What a tracking plan is
A tracking plan is a single document that lists every event your product records, the properties attached to each, the exact moment it fires, and the person accountable for it. It is the contract between the code that emits data and the dashboards that read it. Treat it as a living spec that changes with the product, not a doc you write once and forget. For the one-line version, see tracking plan; this guide covers how to build one.
Why a plan beats ad-hoc tracking
Without a plan, tracking accretes. One engineer fires signup, another fires Sign Up, a third fires user_registered — three names for one action, and every funnel that touches signup silently splits or breaks. That is drift, and it is the main reason analytics stops being trusted. A plan fixes the vocabulary before the code ships, so the numbers you pull in six months still mean what you think. Clean, consistent events are also what an experimentation roadmap runs on — you cannot measure a test against a metric you record three different ways.
Name events object_action, and hold the line
The convention most analytics tools recommend is object_action: the thing, then what happened to it — subscription_started, invite_sent, checkout_completed. Segment, Amplitude, and PostHog each describe a variant (Segment uses 'Object Action', PostHog lowercase snake_case, Amplitude a noun plus a past-tense verb). The exact casing matters far less than picking one and never breaking it. Two rules carry most of the value: keep verb tense consistent, and never build event names dynamically — an event called plan_${name}_upgraded creates one event per customer and is unqueryable.
The 8-10 events that map your funnel
Resist tracking everything. Start with the handful of events that trace a user from first touch to paying — signup, activation, and revenue — and instrument those well before adding depth. Below is a starter set for a typical B2B SaaS; rename them to your product's nouns. Each becomes a row in your plan and, together, they are your first first-party dataset — the raw material for every funnel, cohort, and retention curve you will build.
| Event | When it fires | Why it matters |
|---|---|---|
| account_created | User finishes signup and a record exists | Top of funnel; the denominator for every conversion rate |
| onboarding_started | User enters the first-run flow | Separates signups who begin setup from those who bounce |
| activation_reached | User hits your defined aha moment (e.g. first project shared) | The most predictive early event; validate it, don't assume it |
| feature_used | A core feature is used, with a feature_name property | Depth of engagement; input to segments and retention |
| invite_sent | User invites a teammate | Leading indicator of expansion and stickiness in B2B |
| trial_started | A trial or free plan begins | Opens the revenue funnel; anchors trial-to-paid rate |
| subscription_started | User converts to a paid plan | The revenue moment; ties growth work to money |
| subscription_cancelled | User churns off a paid plan | Churn signal; feeds win-back and retention analysis |
Properties carry the detail; owners keep it clean
Keep events few and generic; push specifics into properties. Instead of a separate event for every plan, fire subscription_started with plan_name and amount_usd properties — one event, richly described, stays queryable. Keep each event's property set lean — a handful you actually query beats dozens you never do. Then decide ownership: in most small teams this sits with a growth engineer or whoever ships instrumentation, and every new event should pass through them so the plan and the code never diverge. Finally, know where the events land. Sending them to a hosted analytics tool or CDP is fast but puts your behavioural data on someone else's servers; keeping it first-party — self-hosted Postgres, your own warehouse — keeps it yours, which is the core open source vs. SaaS trade-off for engagement tooling.