Chapter 6 / 9
Tracking plan and governance
Amplitude accepts everything you send. Where Adjust rejects an undefined token, Amplitude silently creates a new event from a misspelled name. The only guarantee of data quality is a tracking plan written before the integration and maintained after it.
- You will know which fields a tracking plan row should contain.
- You can set up a consistent naming convention.
- You can build a loop that validates the plan before release and protects it after.
Why the plan comes first
In projects without discipline, the number of event names grows over time while the number of questions does not. The same action arrives under three names, each shows up separately in charts, and nobody knows which is right.
The plan loop
What a plan row contains
| Field | Example | Why it's needed |
|---|---|---|
| Event name | Checkout Completed | One name on every platform |
| Trigger | When the payment confirmation screen first appears, once per order | Developer and analyst mean the same moment |
| Source | Server (HTTP API), after the backend verifies payment | Prevents double counting |
| Event properties | order_id string, revenue number, currency string (ISO 4217) | Type and format are fixed |
| User properties updated | orders_count add 1 | Prevents ordering mistakes |
| Platforms | iOS, Android, web | A missing platform becomes visible |
| Question it serves | Cart-to-payment conversion, revenue analysis | Unnecessary events get cut |
| Adjust counterpart | Event token abc123 (S2S) | Consistency between the two tools is tracked |
Naming convention
Which convention you choose matters less than choosing one. A common, readable choice: event names as Object + past-tense verb in Title Case (Product Viewed); property names in snake_case (product_id).
One action, three events
product_view(Android)ProductView(iOS)viewed product(web)Product Viewed - Shoes,Product Viewed - Bags(category in the name)
One event, rich properties
Product Viewedon every platformcategory: "shoes"as a property- Fixed value list:
shoes,bags,accessories - Platform comes from the SDK automatically, not repeated in the name
The few-events, rich-properties principle also makes charts easier to build: "product views by category" is one breakdown on one chart. With one event per category, every new category means a code change and a new chart.
Example plan: an e-commerce app
| Event | Trigger | Source | Event properties | User property effect |
|---|---|---|---|---|
Onboarding Step Viewed | Each onboarding screen shown | SDK | step_number number, step_name string | – |
Signup Completed | Account created | SDK | method string | signup_date setOnce |
Search Performed | Search results listed | SDK | query_length number, results_count number | – |
Product Viewed | Product detail screen opened | SDK | product_id, category, price number, source string | – |
Product Added to Cart | Add to cart succeeded | SDK | product_id, category, price, quantity | – |
Checkout Started | Payment screen opened | SDK | cart_value number, items_count number | – |
Checkout Completed | Payment verified on the backend | HTTP API | order_id, revenue, currency, payment_method | orders_count add 1 |
Push Opened | Notification tapped | SDK | campaign_id string | – |
Subscription Started | First subscription verified | HTTP API | plan, period, revenue | plan set (before the event) |
Subscription Renewed | Store renewal notification received | HTTP API | plan, period, revenue | – |
Properties like source (where the user came to the product from: search, home, push) make funnel and path analysis much stronger. The question to ask while writing the plan: "Along which dimensions will I want to split this event?"
Validation checklist
Before every new release, run these checks in the test project:
- The event name matches the plan exactly (including case and spaces).
- All properties arrive with the right types (numbers as numbers, booleans as booleans).
- The event fires at the moment written in the plan and the expected number of times (one order, one event).
- The user property update happens before or after the event as the plan says.
user_idis correct after login and is reset after logout.- Server events attach to the right user and are not double-counted on resend.
- The production build uses the production API key and the test build the test key.
- The Adjust counterpart of the same event also fires (where needed).
These boxes reset when the page reloads; copy them into your own checklist.
After release: governance
Unplanned data will still arrive: old versions, forgotten test events, typos. Amplitude's data management tools let you do four things with them:
| Action | What it does | When |
|---|---|---|
| Hide | Hides the event in the UI; data stays | Events no longer used but whose history should be kept |
| Block | Stops processing this event in future | Test or broken events |
| Merge / transform | Shows different names as one event in analysis | Historical spelling variants like product_view and Product Viewed |
| Validate against the plan | Flags events and properties outside the plan | Ongoing quality monitoring |
The current names of these actions in Amplitude, which ones apply retroactively and which plan they are in can change. In particular, check whether "block" touches historical data before telling a client.
In Adjust, the event token list is already a natural tracking plan: you can't send an event without a token. In Amplitude you have to maintain that list yourself. The most practical way is to keep both tools' events in the same table: one column for the Amplitude name and properties, one for the Adjust token and parameters. That way an event added to one tool and forgotten in the other is visible immediately.
Starting from a client's current Adjust event list, draft a tracking plan with the template above. Fill in the "question it serves" column for each event. Events where you can't fill that column may not be worth moving to Amplitude.