Tracking plan
The document that pins down exactly which events you fire, what properties they carry, and what each one means. The cure for event-name chaos.
See it
What it is
One table, one row per event: the name, the exact trigger (which user action, which file), the properties with their types and allowed values, which platforms send it, who owns it, and the question it exists to answer. It can live in a sheet, in Notion, as YAML in the repo, or in a tool built for it (Avo, Segment Protocols, Mixpanel Lexicon) that can check live traffic against the spec.
Write it before you instrument anything, working backwards from the questions you actually want answered rather than forwards from the UI. The plan is also where you settle naming once: object plus action in past tense, snake_case by default (checkout_completed), and stop. The one good reason to deviate is a tool whose own docs and UI assume Title Case, like Segment or Amplitude, in which case follow the tool and record that in the plan. Renaming events later splits your history in half, so the bike-shedding is cheapest on day one.
Gotcha: an unenforced tracking plan rots in a week. It only stays true if something checks it: typed track() wrappers generated from the spec, a CI test that fails on unknown event names, or a pipeline that rejects events with missing required properties. A plan that lives only in a doc becomes archaeology, not documentation.
Ask AI for it
Write a tracking plan for [product or feature] as a markdown table with these columns: event name (object plus action, past tense, snake_case unless the analytics tool in this project documents another casing, in which case use that and note it at the top), trigger (the exact user action and where in the code it fires), properties (name, type, example value, required or optional), user properties updated, and the analytics question it answers. Cover the whole primary flow from first visit through activation in 12 to 20 events, no duplicates, no events that just restate a pageview. Then generate a TypeScript module that turns every row into a typed track() wrapper, so a typo in an event name fails to compile.