Analytics and tracking skill 01 of 6
Event tracking plan
An event tracking plan is the contract between the people who fire events and the people who read them. This skill makes an AI agent design it as one versioned spec: events named once, every property typed, identity defined, and each event mapped to its warehouse table.
By Afeez Adebayo, Marketing, SEO & Growth Expert with 10+ years of experience.
Created 5 November 2026. Updated 5 November 2026. Free to use under CC BY 4.0.
An event tracking plan is the contract between the people who fire events and the people who analyse them. When that contract is missing, the same action gets logged as signup, sign_up, Signed Up and user_registration, properties change type between releases, and every funnel quietly drops the rows that do not match. This skill makes an AI agent design the plan as a single, versioned, machine-readable specification, so events are named once, every property is typed, identity is defined, and each event has a known home in the warehouse.
It treats the plan as data engineering, not a wishlist. The output is a spec an agent and a human can both read: event name, when it fires, who owns it, each property with a type and allowed values, the identity scope, the consent class, and the downstream table. Analytics platforms treat two spellings or two casings of a name as two different events, so the plan's job is to make one decision per name and hold it.
When to use this skill, and when not to
Use this skill to design a new tracking plan, to audit and consolidate a messy one, to write a data contract or event schema, to set naming conventions, or to prepare a spec for Segment Protocols, Amplitude, Mixpanel, Avo or Snowplow. It fires on an event taxonomy, a data dictionary, a dataLayer spec, duplicate or inconsistent event names, or "what should we track".
Do not use it to decide which events a growth team should prioritise against a north star metric, which is the marketing tracking-plan skill. Do not use it for ad-platform conversions and the Conversions API, which is conversion-tracking-capi. Do not use it to tag campaign links, which is the sibling utm-campaign-tracking. Do not use it to analyse the data once collected, which is funnel-analysis or cohort-retention-analysis. Do not use it to confirm that live tracking fires correctly in a browser or in production, which is the sibling analytics-qa-validation. When a request spans two of these, design the plan here and hand off the rest by name.
Inputs the agent must have before starting
Ask for these in one message, and do not invent them:
- The destinations the data flows to, in order: the collection tool (GA4, Segment, Amplitude, Mixpanel, Snowplow, RudderStack) and the warehouse or lake if there is one. Casing and limits depend on this.
- The product and the decisions the data must support, in plain words. A plan serves questions, not completeness.
- Any existing events and their current names, so consolidation can be grounded rather than guessed. A live export beats a description.
- Who owns instrumentation (usually data or analytics engineering) and how changes get shipped.
- Whether the business is B2B, because that adds a group or account identity.
- The consent and privacy regime, so each property can be classed and no personal data is written where it should not be.
If the destination is unknown, stop and ask: the single most consequential rule in the plan, casing, cannot be set without it.
Raw SKILL.md file
This is the exact file agents read, including the credit header and licence notice. Save it as event-tracking-plan/SKILL.md.
--- name: event-tracking-plan description: Designs an event tracking plan as a versioned data contract for product and web analytics, so an AI agent names events and properties consistently, types every property, defines identity and consent, and maps each event to a downstream warehouse table. Use when the request mentions an event tracking plan, event taxonomy, data dictionary, event schema, naming conventions for events, "what events should we track", a dataLayer or event spec, Segment Protocols, Amplitude or Mixpanel taxonomy, Avo, Snowplow schemas, or cleaning up duplicate or inconsistent event names. Do NOT use for choosing which events support growth metrics (use the marketing tracking-plan skill), ad-platform conversion tracking (conversion-tracking-capi), campaign URL tagging (utm-campaign-tracking), analysing collected data (funnel-analysis, cohort-retention-analysis), or validating that live tracking fires correctly (analytics-qa-validation). license: CC BY 4.0. Free to use and adapt with credit to Afeez Adebayo. metadata: author: Afeez Adebayo website: https://afeezadebayo.com linkedin: https://www.linkedin.com/in/afeez-adebayo/ source: https://afeezadebayo.com/skills-md/data/analytics-tracking/event-tracking-plan/ category: data subcategory: analytics-tracking version: 1.0.0 created: 5 November 2026 updated: 5 November 2026 --- # Event tracking plan An event tracking plan is the contract between the people who fire events and the people who analyse them. When that contract is missing, the same action gets logged as `signup`, `sign_up`, `Signed Up` and `user_registration`, properties change type between releases, and every funnel quietly drops the rows that do not match. This skill makes an AI agent design the plan as a single, versioned, machine-readable specification, so events are named once, every property is typed, identity is defined, and each event has a known home in the warehouse. It treats the plan as data engineering, not a wishlist. The output is a spec an agent and a human can both read: event name, when it fires, who owns it, each property with a type and allowed values, the identity scope, the consent class, and the downstream table. Analytics platforms treat two spellings or two casings of a name as two different events, so the plan's job is to make one decision per name and hold it. ## When to use this skill, and when not to Use this skill to design a new tracking plan, to audit and consolidate a messy one, to write a data contract or event schema, to set naming conventions, or to prepare a spec for Segment Protocols, Amplitude, Mixpanel, Avo or Snowplow. It fires on an event taxonomy, a data dictionary, a dataLayer spec, duplicate or inconsistent event names, or "what should we track". Do not use it to decide which events a growth team should prioritise against a north star metric, which is the marketing `tracking-plan` skill. Do not use it for ad-platform conversions and the Conversions API, which is `conversion-tracking-capi`. Do not use it to tag campaign links, which is the sibling `utm-campaign-tracking`. Do not use it to analyse the data once collected, which is `funnel-analysis` or `cohort-retention-analysis`. Do not use it to confirm that live tracking fires correctly in a browser or in production, which is the sibling `analytics-qa-validation`. When a request spans two of these, design the plan here and hand off the rest by name. ## Inputs the agent must have before starting Ask for these in one message, and do not invent them: 1. The destinations the data flows to, in order: the collection tool (GA4, Segment, Amplitude, Mixpanel, Snowplow, RudderStack) and the warehouse or lake if there is one. Casing and limits depend on this. 2. The product and the decisions the data must support, in plain words. A plan serves questions, not completeness. 3. Any existing events and their current names, so consolidation can be grounded rather than guessed. A live export beats a description. 4. Who owns instrumentation (usually data or analytics engineering) and how changes get shipped. 5. Whether the business is B2B, because that adds a group or account identity. 6. The consent and privacy regime, so each property can be classed and no personal data is written where it should not be. If the destination is unknown, stop and ask: the single most consequential rule in the plan, casing, cannot be set without it. ## Workflow ### Step 1. Fix the naming grammar before naming anything Choose one grammar and one casing, write them at the top of the plan, and apply them to every event without exception. - Grammar: `object` then `past-tense action`, from the user's point of view. `order_completed`, not `complete_order` or `order` or `checkout_success`. Describe what happened, not what the system did (`message_sent`, not `message_delivered`), unless the system event is the thing you measure. - Casing: pick one per destination and never mix, because every major tool treats `Sign Up`, `sign_up` and `signUp` as three distinct events. GA4 requires `snake_case` for event and parameter names. Segment's convention is Title Case event names with `snake_case` properties. Amplitude's default is Title Case. Mixpanel, Snowplow and warehouse-first stacks favour `snake_case` throughout. If the data lands in a warehouse, prefer `snake_case` end to end, because it survives SQL without quoting. Record the decision as a one-line rule. - One concept, one name, everywhere. If `order_id` identifies an order on one event, it is `order_id` on every event, never `orderId` or `transaction_id` elsewhere. - Distinct concepts get distinct names. `login_method` and `payment_method` are not both `method`; `item_type` and `payment_type` are not both `type`. ### Step 2. Choose the events, and prefer standard events Track the actions tied to the decisions from the inputs, not every click. Reach for standard events first, because they switch on built-in reports. - In GA4, use the recommended events where one fits: `login`, `sign_up`, `search` (which needs a `search_term` parameter), `select_content`, `share`, and the ecommerce set (`add_to_cart`, `purchase` and so on). Ecommerce events need `currency`, `value` and an `items` array, each item carrying `item_id` or `item_name`, with `value` equal to the sum of price times quantity, excluding shipping and tax. Verify the current recommended-event list and its required parameters in the GA4 docs before relying on specific names. - In Segment, reuse the ecommerce spec reserved names such as `Order Completed` and `Product Added`. - Keep events generic and let properties carry the detail. One `page_viewed` with a `page_name` property beats `home_page_viewed` and `pricing_page_viewed` as separate events. One `error_encountered` with an `error_type` beats an event per error. - A/B test assignment is a user property, not an event. ### Step 3. Type every property and define allowed values A property without a type is a future bug. For each property set four things: name, type, whether it is required, and the allowed values or range. - IDs are strings, always. `"12345"`, not `12345`, so a leading zero or a non-numeric id never breaks the column. - Counts and amounts are numbers; flags are booleans; enumerations are strings with a listed set of allowed values. - Timestamps are ISO 8601 strings, and time-of-event properties use an `_at` suffix (`created_at`, `completed_at`). - Include units in the name: `price_usd`, `video_duration_seconds`, `file_size_bytes`. A bare `duration` is unreadable six months later. - Decide null handling once and apply it to every property: either omit the key when there is no value, or send an explicit `null`, or send a single sentinel such as `"unknown"`. Never mix the three. Inconsistent null handling is one of the most common causes of broken filters and funnels. - Never generate property keys dynamically. `feature_1`, `feature_2`, `feature_3` each become a new warehouse column; use one `feature_name` property with multiple events or an array instead. - Classify each property for privacy: is it personal data, pseudonymous, or neutral. Personal data such as email, full name, card number or raw IP does not belong in event properties; use a hashed or opaque id and record the class in the plan. ### Step 4. Write the identity contract Identity is part of the plan, not an afterthought, because a broken identity join silently splits one person into many. - Anonymous visitors carry only an anonymous or device id. Never set a `user_id` before the person authenticates. - On sign-up or login, issue the identify-and-merge call so the pre-login anonymous activity joins to the stable `user_id`. - Use the same `user_id` across devices, and reset it on logout so the next user on a shared device is not merged in. - For server-side events, include a deduplication id (an `insert_id`, or a shared key such as `order_id` used by both browser and server) so the same event counted twice is collapsed. Record the dedup window your tool uses. - For B2B, add a group or account identity (`account_id` or `org_id`) and send it on the events where it matters. ### Step 5. Map each event to its downstream table and respect the limits Record, for every event, the warehouse table or model it lands in. One event is usually one table; this is what makes the plan a data contract rather than a naming list. Hold the plan inside the collection tool's hard limits, which are version-dependent, so verify the current numbers before relying on them. As last checked on 5 November 2026: GA4 caps event names at 40 characters, parameter names at 40, most parameter values at 100 (with `page_location` up to 1,000, `page_referrer` up to 420, `page_title` up to 300), 25 parameters per event, and 25 user properties (name up to 24, value up to 36). GA4 app streams cap distinct event names at 500 per user; web streams have no such cap. Reserved prefixes such as `ga_`, `google_` and `firebase_` cannot be used; confirm the current reserved list in the GA4 docs. Mixpanel has a soft limit near 5,000 distinct event names and allows up to 255 properties per event, with names and values up to 255 characters. Design inside these, not up to them. ### Step 6. Version the plan and set the change process - Store the plan as a machine-readable spec, not a slide. A JSON Schema per event (the Snowplow and Iglu model, versioned as `1-0-0`), a Segment Protocols tracking plan, an Avo workspace, or a schema file in git are all valid. A versioned file in git with CI validation is the free-stack equivalent of a paid governance tool. - Add new properties as optional; never change a property's type or an event's meaning in place. When a change is breaking, ship a new version of the event and sunset the old one with a deprecation window. - Deprecate an event only when it has no recent volume and no recent queries together. A safe window is six to twelve months of silence. - Run every change through one process: request, review, implement, QA (hand to `analytics-qa-validation`), publish the plan, then monitor. Deleting or blocking an event changes what data exists going forward and cannot be undone for the gap it creates, so treat deletion and hard blocks as irreversible and get explicit human confirmation before either. Default to proposing the plan as a draft. ## Worked example A B2B SaaS team sends an export with 410 distinct event names across GA4 and the warehouse. The obvious move is to rename everything to one casing and move on. That misses the real problems. Running the workflow: Step 1 sets `snake_case` end to end, because the data lands in BigQuery. Step 2 finds `signup`, `sign_up`, `SignUp`, `user_registered` and `account_created` all firing on the same action; they collapse to one `sign_up` with a `method` property. Near-duplicate `home_viewed`, `pricing_viewed` and `docs_viewed` collapse to `page_viewed` with `page_name`. Step 3 catches `plan_price` sent as `"29.00"` on web and `29` on server; it is fixed to a number named `plan_price_usd`, and `account_id` is retyped from number to string. A column `signup_source` mixing `null`, empty string and `"none"` is standardised to omit-when-absent. Step 4 finds the app set `user_id` to the anonymous id before login, splitting each user in two; the contract moves the `user_id` to the first authenticated event and adds an identify-and-merge. Step 5 maps the 62 surviving events to tables and flags that `search` was missing its `search_term`, so the GA4 search report was empty. Step 6 writes the lot to a versioned JSON Schema in git with a CI check. The result is 62 events from 410, every property typed, identity fixed, and a spec the next engineer cannot drift from without the CI failing. The count fell because duplicates were merged, not because data was thrown away. ## Templates you can use verbatim Event contract row (one per event): ``` event: order_completed fires_when: the payment provider confirms a successful charge owner: checkout squad identity: user_id required; account_id for B2B consent_class: analytics_storage destination_table: analytics.fct_order_completed properties: - name: order_id type: string required: yes notes: joins to orders table - name: revenue_usd type: number required: yes notes: excludes tax and shipping - name: currency type: string required: yes allowed: ISO 4217 codes - name: item_count type: integer required: yes - name: coupon_code type: string required: no null_rule: omit when absent - name: payment_method type: string required: yes allowed: card, paypal, bank_transfer ``` Naming rules block to paste at the top of any plan: ``` Grammar: object_then_past_tense_action, from the user's point of view. Casing: snake_case for event and property names (warehouse-first). One casing, no exceptions. IDs: strings. Amounts: numbers with a unit in the name (revenue_usd). Timestamps: ISO 8601, _at suffix. Nulls: omit the key when there is no value. Never send empty string or a mix. One concept = one name everywhere. Distinct concepts = distinct names. No dynamic values in names. No dynamically generated property keys. ``` Prompt to start a plan: "Design an event tracking plan for [product] flowing to [tool] then [warehouse]. Here are the decisions it must support and the current events: [paste]. Return a versioned contract with typed properties, the identity rules and the destination tables." ## Failure modes and anti-patterns 1. Naming decided per event instead of once. You spot it when `method`, `type` and `source` mean different things on different events. Fix it by setting the grammar and casing in Step 1 and applying them everywhere before a single event is named. 2. Casing mixed across a destination. You spot it in the tool as `Sign Up`, `sign_up` and `signUp` reported as three events with split numbers. Fix it by choosing one casing per destination and consolidating; in a warehouse, lowercase everything. 3. Properties untyped or null-handled inconsistently. You spot it when a filter returns far fewer rows than expected or a funnel breaks at one step. Fix it by typing every property and choosing one null rule in Step 3. 4. Identity set too early. You spot it when user counts are implausibly high and one person appears as many. Fix it by never setting `user_id` before authentication and adding an identify-and-merge at login. 5. Events added forever with no governance. You spot it as event-name sprawl and duplicate meanings creeping back within three months. Fix it with the versioned spec and the request-review-implement-QA-publish-monitor process in Step 6. ## Quality bar for the plan Before handing over, confirm every item: - One grammar and one casing per destination are stated in writing and hold for every event. - Every property has a name, a type, a required flag, and allowed values or a range. - Every property has a null rule, and the rule is the same across the plan. - Identity is defined: anonymous, authenticated, cross-device, logout reset, server dedup, and group for B2B. - Each event names its downstream table. - Standard or recommended events are reused wherever one fits, with their required parameters present. - The plan sits inside the tool's current limits, and any version-dependent number was verified, not assumed. - The plan is a versioned, machine-readable file with a change process, and no deletion or hard block ships without human confirmation. - No event property carries personal data; privacy class is recorded for each property. ## Tool-specific appendix ``` GA4 - snake_case required for event and parameter names. Limits as last checked 5 Nov 2026: event name <=40, param name <=40, param value <=100 (page_location <=1000, page_referrer <=420, page_title <=300), 25 params per event, 25 user properties. App streams cap distinct event names at 500 per user; web has no cap. - Reserved prefixes ga_, google_, firebase_ cannot be used. Verify the reserved-name list in the GA4 docs. - Reuse recommended events (login, sign_up, search with search_term, purchase with currency/value/items). Segment - Convention: Title Case event names, snake_case properties. Reuse ecommerce spec reserved names. - Protocols enforces the plan: non-conforming events raise violations; strict controls block and can quarantine them to a separate source; transformations rename without code changes. Business-tier add-on. Amplitude - Default Title Case, [Object] [Past-Tense Verb]. Different casings are different events. IDs as strings. Govern tracks event states (Planned, Live, Blocked, Unexpected, Deleted). Blocking reduces volume but not the distinct-type count; only deletion reduces the type count. Mixpanel - snake_case recommended for warehouse export. Case-sensitive. Soft limit ~5,000 distinct event names, 255 properties per event, names and values up to 255 chars. Lexicon renames are display-only. Snowplow - Self-describing JSON Schema per event, Iglu-versioned (1-0-0); invalid events are routed to failed events, so bad data never reaches the warehouse. Strongest option when validation-before-load matters. Avo - Enforces naming: blocks events differing only by casing, warns on similar names, keeps a global property namespace, and forbids an event property sharing a name with a user property. Inspector flags shipped events that do not match the plan. ``` ## Sources - Amplitude, Data planning playbook and taxonomy agent skill (naming, property types, event states, volume vs type count). Last verified 5 November 2026. - Segment (Twilio) Protocols and tracking-plan best practices (object-action, Title Case events, violations, block, quarantine, transformations). Last verified 5 November 2026. - Mixpanel, Events and properties (snake_case, case sensitivity, limits, super properties). Last verified 5 November 2026. - Avo, Naming conventions (casing enforcement, global namespace, controlled vocabulary). Last verified 5 November 2026. - Snowplow, Schemas and Iglu (self-describing JSON Schema, versioning, failed events). Last verified 5 November 2026. - Google Analytics 4, Event collection limits and Recommended events references (name and parameter limits, recommended and ecommerce events). Last verified 5 November 2026; limits and reserved names are version-dependent, so re-check the GA4 docs before relying on specific numbers. - Related skills: marketing tracking-plan (growth-metric selection), conversion-tracking-capi (ad conversions), and the sibling skills utm-campaign-tracking and analytics-qa-validation.
Workflow
Step 1. Fix the naming grammar before naming anything
Choose one grammar and one casing, write them at the top of the plan, and apply them to every event without exception.
- Grammar:
objectthenpast-tense action, from the user's point of view.order_completed, notcomplete_orderororderorcheckout_success. Describe what happened, not what the system did (message_sent, notmessage_delivered), unless the system event is the thing you measure. - Casing: pick one per destination and never mix, because every major tool treats
Sign Up,sign_upandsignUpas three distinct events. GA4 requiressnake_casefor event and parameter names. Segment's convention is Title Case event names withsnake_caseproperties. Amplitude's default is Title Case. Mixpanel, Snowplow and warehouse-first stacks favoursnake_casethroughout. If the data lands in a warehouse, prefersnake_caseend to end, because it survives SQL without quoting. Record the decision as a one-line rule. - One concept, one name, everywhere. If
order_ididentifies an order on one event, it isorder_idon every event, neverorderIdortransaction_idelsewhere. - Distinct concepts get distinct names.
login_methodandpayment_methodare not bothmethod;item_typeandpayment_typeare not bothtype.
Step 2. Choose the events, and prefer standard events
Track the actions tied to the decisions from the inputs, not every click. Reach for standard events first, because they switch on built-in reports.
- In GA4, use the recommended events where one fits:
login,sign_up,search(which needs asearch_termparameter),select_content,share, and the ecommerce set (add_to_cart,purchaseand so on). Ecommerce events needcurrency,valueand anitemsarray, each item carryingitem_idoritem_name, withvalueequal to the sum of price times quantity, excluding shipping and tax. Verify the current recommended-event list and its required parameters in the GA4 docs before relying on specific names. - In Segment, reuse the ecommerce spec reserved names such as
Order CompletedandProduct Added. - Keep events generic and let properties carry the detail. One
page_viewedwith apage_nameproperty beatshome_page_viewedandpricing_page_viewedas separate events. Oneerror_encounteredwith anerror_typebeats an event per error. - A/B test assignment is a user property, not an event.
Step 3. Type every property and define allowed values
A property without a type is a future bug. For each property set four things: name, type, whether it is required, and the allowed values or range.
- IDs are strings, always.
"12345", not12345, so a leading zero or a non-numeric id never breaks the column. - Counts and amounts are numbers; flags are booleans; enumerations are strings with a listed set of allowed values.
- Timestamps are ISO 8601 strings, and time-of-event properties use an
_atsuffix (created_at,completed_at). - Include units in the name:
price_usd,video_duration_seconds,file_size_bytes. A baredurationis unreadable six months later. - Decide null handling once and apply it to every property: either omit the key when there is no value, or send an explicit
null, or send a single sentinel such as"unknown". Never mix the three. Inconsistent null handling is one of the most common causes of broken filters and funnels. - Never generate property keys dynamically.
feature_1,feature_2,feature_3each become a new warehouse column; use onefeature_nameproperty with multiple events or an array instead. - Classify each property for privacy: is it personal data, pseudonymous, or neutral. Personal data such as email, full name, card number or raw IP does not belong in event properties; use a hashed or opaque id and record the class in the plan.
Step 4. Write the identity contract
Identity is part of the plan, not an afterthought, because a broken identity join silently splits one person into many.
- Anonymous visitors carry only an anonymous or device id. Never set a
user_idbefore the person authenticates. - On sign-up or login, issue the identify-and-merge call so the pre-login anonymous activity joins to the stable
user_id. - Use the same
user_idacross devices, and reset it on logout so the next user on a shared device is not merged in. - For server-side events, include a deduplication id (an
insert_id, or a shared key such asorder_idused by both browser and server) so the same event counted twice is collapsed. Record the dedup window your tool uses. - For B2B, add a group or account identity (
account_idororg_id) and send it on the events where it matters.
Step 5. Map each event to its downstream table and respect the limits
Record, for every event, the warehouse table or model it lands in. One event is usually one table; this is what makes the plan a data contract rather than a naming list.
Hold the plan inside the collection tool's hard limits, which are version-dependent, so verify the current numbers before relying on them. As last checked on 5 November 2026: GA4 caps event names at 40 characters, parameter names at 40, most parameter values at 100 (with page_location up to 1,000, page_referrer up to 420, page_title up to 300), 25 parameters per event, and 25 user properties (name up to 24, value up to 36). GA4 app streams cap distinct event names at 500 per user; web streams have no such cap. Reserved prefixes such as ga_, google_ and firebase_ cannot be used; confirm the current reserved list in the GA4 docs. Mixpanel has a soft limit near 5,000 distinct event names and allows up to 255 properties per event, with names and values up to 255 characters. Design inside these, not up to them.
Step 6. Version the plan and set the change process
- Store the plan as a machine-readable spec, not a slide. A JSON Schema per event (the Snowplow and Iglu model, versioned as
1-0-0), a Segment Protocols tracking plan, an Avo workspace, or a schema file in git are all valid. A versioned file in git with CI validation is the free-stack equivalent of a paid governance tool. - Add new properties as optional; never change a property's type or an event's meaning in place. When a change is breaking, ship a new version of the event and sunset the old one with a deprecation window.
- Deprecate an event only when it has no recent volume and no recent queries together. A safe window is six to twelve months of silence.
- Run every change through one process: request, review, implement, QA (hand to
analytics-qa-validation), publish the plan, then monitor. Deleting or blocking an event changes what data exists going forward and cannot be undone for the gap it creates, so treat deletion and hard blocks as irreversible and get explicit human confirmation before either. Default to proposing the plan as a draft.
Worked example
A B2B SaaS team sends an export with 410 distinct event names across GA4 and the warehouse. The obvious move is to rename everything to one casing and move on. That misses the real problems.
Running the workflow: Step 1 sets snake_case end to end, because the data lands in BigQuery. Step 2 finds signup, sign_up, SignUp, user_registered and account_created all firing on the same action; they collapse to one sign_up with a method property. Near-duplicate home_viewed, pricing_viewed and docs_viewed collapse to page_viewed with page_name. Step 3 catches plan_price sent as "29.00" on web and 29 on server; it is fixed to a number named plan_price_usd, and account_id is retyped from number to string. A column signup_source mixing null, empty string and "none" is standardised to omit-when-absent. Step 4 finds the app set user_id to the anonymous id before login, splitting each user in two; the contract moves the user_id to the first authenticated event and adds an identify-and-merge. Step 5 maps the 62 surviving events to tables and flags that search was missing its search_term, so the GA4 search report was empty. Step 6 writes the lot to a versioned JSON Schema in git with a CI check.
The result is 62 events from 410, every property typed, identity fixed, and a spec the next engineer cannot drift from without the CI failing. The count fell because duplicates were merged, not because data was thrown away.
Templates you can use verbatim
Event contract row (one per event):
event: order_completed
fires_when: the payment provider confirms a successful charge
owner: checkout squad
identity: user_id required; account_id for B2B
consent_class: analytics_storage
destination_table: analytics.fct_order_completed
properties:
- name: order_id type: string required: yes notes: joins to orders table
- name: revenue_usd type: number required: yes notes: excludes tax and shipping
- name: currency type: string required: yes allowed: ISO 4217 codes
- name: item_count type: integer required: yes
- name: coupon_code type: string required: no null_rule: omit when absent
- name: payment_method type: string required: yes allowed: card, paypal, bank_transferNaming rules block to paste at the top of any plan:
Grammar: object_then_past_tense_action, from the user's point of view.
Casing: snake_case for event and property names (warehouse-first). One casing, no exceptions.
IDs: strings. Amounts: numbers with a unit in the name (revenue_usd). Timestamps: ISO 8601, _at suffix.
Nulls: omit the key when there is no value. Never send empty string or a mix.
One concept = one name everywhere. Distinct concepts = distinct names.
No dynamic values in names. No dynamically generated property keys.Prompt to start a plan: "Design an event tracking plan for [product] flowing to [tool] then [warehouse]. Here are the decisions it must support and the current events: [paste]. Return a versioned contract with typed properties, the identity rules and the destination tables."
Failure modes and anti-patterns
- Naming decided per event instead of once. You spot it when
method,typeandsourcemean different things on different events. Fix it by setting the grammar and casing in Step 1 and applying them everywhere before a single event is named. - Casing mixed across a destination. You spot it in the tool as
Sign Up,sign_upandsignUpreported as three events with split numbers. Fix it by choosing one casing per destination and consolidating; in a warehouse, lowercase everything. - Properties untyped or null-handled inconsistently. You spot it when a filter returns far fewer rows than expected or a funnel breaks at one step. Fix it by typing every property and choosing one null rule in Step 3.
- Identity set too early. You spot it when user counts are implausibly high and one person appears as many. Fix it by never setting
user_idbefore authentication and adding an identify-and-merge at login. - Events added forever with no governance. You spot it as event-name sprawl and duplicate meanings creeping back within three months. Fix it with the versioned spec and the request-review-implement-QA-publish-monitor process in Step 6.
Quality bar for the plan
Before handing over, confirm every item:
- One grammar and one casing per destination are stated in writing and hold for every event.
- Every property has a name, a type, a required flag, and allowed values or a range.
- Every property has a null rule, and the rule is the same across the plan.
- Identity is defined: anonymous, authenticated, cross-device, logout reset, server dedup, and group for B2B.
- Each event names its downstream table.
- Standard or recommended events are reused wherever one fits, with their required parameters present.
- The plan sits inside the tool's current limits, and any version-dependent number was verified, not assumed.
- The plan is a versioned, machine-readable file with a change process, and no deletion or hard block ships without human confirmation.
- No event property carries personal data; privacy class is recorded for each property.
Tool-specific appendix
GA4
- snake_case required for event and parameter names. Limits as last checked 5 Nov 2026: event name <=40,
param name <=40, param value <=100 (page_location <=1000, page_referrer <=420, page_title <=300),
25 params per event, 25 user properties. App streams cap distinct event names at 500 per user; web has no cap.
- Reserved prefixes ga_, google_, firebase_ cannot be used. Verify the reserved-name list in the GA4 docs.
- Reuse recommended events (login, sign_up, search with search_term, purchase with currency/value/items).
Segment
- Convention: Title Case event names, snake_case properties. Reuse ecommerce spec reserved names.
- Protocols enforces the plan: non-conforming events raise violations; strict controls block and can quarantine
them to a separate source; transformations rename without code changes. Business-tier add-on.
Amplitude
- Default Title Case, [Object] [Past-Tense Verb]. Different casings are different events. IDs as strings.
Govern tracks event states (Planned, Live, Blocked, Unexpected, Deleted). Blocking reduces volume but not
the distinct-type count; only deletion reduces the type count.
Mixpanel
- snake_case recommended for warehouse export. Case-sensitive. Soft limit ~5,000 distinct event names,
255 properties per event, names and values up to 255 chars. Lexicon renames are display-only.
Snowplow
- Self-describing JSON Schema per event, Iglu-versioned (1-0-0); invalid events are routed to failed events,
so bad data never reaches the warehouse. Strongest option when validation-before-load matters.
Avo
- Enforces naming: blocks events differing only by casing, warns on similar names, keeps a global property
namespace, and forbids an event property sharing a name with a user property. Inspector flags shipped
events that do not match the plan.Sources
- Amplitude, Data planning playbook and taxonomy agent skill (naming, property types, event states, volume vs type count). Last verified 5 November 2026.
- Segment (Twilio) Protocols and tracking-plan best practices (object-action, Title Case events, violations, block, quarantine, transformations). Last verified 5 November 2026.
- Mixpanel, Events and properties (snake_case, case sensitivity, limits, super properties). Last verified 5 November 2026.
- Avo, Naming conventions (casing enforcement, global namespace, controlled vocabulary). Last verified 5 November 2026.
- Snowplow, Schemas and Iglu (self-describing JSON Schema, versioning, failed events). Last verified 5 November 2026.
- Google Analytics 4, Event collection limits and Recommended events references (name and parameter limits, recommended and ecommerce events). Last verified 5 November 2026; limits and reserved names are version-dependent, so re-check the GA4 docs before relying on specific numbers.
- Related skills: marketing tracking-plan (growth-metric selection), conversion-tracking-capi (ad conversions), and the sibling skills utm-campaign-tracking and analytics-qa-validation.
On this page
- When to use this skill, and when not to
- Who it is for
- What is inside
- Example prompts
- Example output
- What the agent needs from you
- How to install and use it
- How to design an event tracking plan step by step
- Worked example
- Situations this skill handles
- What makes this skill different
- Common mistakes
- Related skills
- Frequently asked questions
- Changelog
When to use this skill, and when not to
Use this skill when you need to decide what to track and how to name it, or to clean up a taxonomy that has drifted. It fires on an event tracking plan, an event taxonomy, a data dictionary, a dataLayer spec, naming conventions, or duplicate and inconsistent event names across GA4, Segment, Amplitude, Mixpanel, Avo or Snowplow. Do not use it to pick which events a growth team should prioritise, to track ad conversions, or to analyse the data once it is collected.
Who it is for
Analytics engineers, data engineers, product analysts and anyone pointing an AI agent at instrumentation. You do not need to know every tool; you need to know what the data must answer and where it lands. The skill asks for the destinations and the current events, then does the naming, typing and identity work to a standard a careful data team would accept.
What is inside
A six-step workflow with decision rules, not slogans. It sets one naming grammar and one casing per destination, picks events and reuses standard ones, types every property with allowed values and a single null rule, writes the identity contract, maps each event to a warehouse table inside the tool’s limits, and versions the plan with a change process. A worked example, copy-paste templates, the five ways it goes wrong, and a tool-by-tool appendix come with it.
Example prompts
“Design an event tracking plan for our SaaS app flowing to GA4 then BigQuery.” “We have 400 event names and half are duplicates, consolidate them.” “Write a data contract for checkout events with typed properties.” “Set naming conventions for our Segment plan.”
Example output
The skill returns a spec, not just advice: a naming rules block, then one contract row per event with its trigger, owner, identity scope, consent class, destination table and a typed property list with allowed values. It states what it merged and why, and flags anything it needs confirmed before a destructive change.
What the agent needs from you
The destinations in order (the collection tool and the warehouse), the decisions the data must support, an export of the current events if one exists, who owns instrumentation, whether the business is B2B, and the consent regime. The casing rule cannot be set without knowing the destination, so the agent asks for that first rather than guessing.
How to install and use it
In the Claude apps, download the SKILL.md from this page, put it in a folder named event-tracking-plan, and upload that folder. In Claude Code, Codex and other Agent Skills tools, copy the folder into your skills directory. Then ask the agent to design or clean up your tracking plan and it loads the skill on its own.
How to design an event tracking plan step by step
Install the skill as event-tracking-plan/SKILL.md. Give the agent the destinations and the decisions the plan must support, and paste any current events. It fixes the naming grammar and casing first, chooses and consolidates events, types every property, writes the identity rules, maps events to tables within the tool’s limits, and hands back a versioned contract. Confirm before it deletes or blocks any event, because that cannot be undone for the gap it leaves.
Worked example
Handed 410 event names across GA4 and BigQuery, the skill does not just re-case them. It collapses five spellings of sign-up into one event, merges three near-duplicate page views into one with a page_name property, retypes a price sent as a string on web and a number on server, moves a user_id that was set before login so users stop splitting in two, and finds that search was missing its search_term. The result is 62 clean events with every property typed and a spec the next engineer cannot drift from.
Situations this skill handles
| Situation | What the skill does |
|---|---|
| Same action logged under many names | Collapses them to one event and records the rule so they cannot return |
| A property typed differently on web and server | Fixes one type and one null rule across every event |
| user_id set before login | Moves identity to the first authenticated event and adds identify-and-merge |
| A standard action like sign-up or purchase | Reuses the tool’s recommended event so built-in reports work |
| A plan with no owner or version | Writes it as a versioned spec with a request, review, implement, QA and publish process |
What makes this skill different
Most taxonomy guides stop at object-action naming. This skill adds the parts that actually break analysis: a casing decision per destination, a type and a single null rule for every property, an identity contract, and a map from each event to its warehouse table. It stays tool-agnostic, with the GA4, Segment, Amplitude, Mixpanel, Snowplow and Avo specifics fenced into an appendix instead of tying you to one product.
Common mistakes
Deciding naming per event instead of once, so method and type mean different things in different places. Mixing casing, so one action reports as three events with split numbers. Leaving properties untyped or null-handled three different ways, which quietly breaks filters and funnels. Setting user_id before login, which doubles your user count. Adding events forever with no governance, so duplicates creep back within three months.
Related skills
Pair it with utm-campaign-tracking, which governs the source and medium data that arrives as an inbound contract, and analytics-qa-validation, which checks that the plan is actually firing. For choosing which events serve a growth metric, use the marketing tracking-plan skill; for ad-platform conversions, conversion-tracking-capi; for analysing the data, funnel-analysis and cohort-retention-analysis.
Frequently asked questions
What is an event tracking plan?
It is a single document that defines every event you collect, what each one means, when it fires, and the typed properties it carries, plus the identity and consent rules. It is the shared contract between the people who instrument the product and the people who analyse the data, so a number means the same thing to everyone.
Should I use snake_case or Title Case for event names?
Pick one per destination and never mix, because every tool treats different casings as different events. GA4 needs snake_case; Segment’s convention is Title Case events with snake_case properties; Amplitude defaults to Title Case. If the data lands in a warehouse, snake_case end to end is easiest because it survives SQL without quoting.
How many events should we track?
Track the actions tied to decisions, not every click. Keep events generic and let properties carry the detail, so one page_viewed with a page_name beats a separate event per page. Teams that consolidate often cut hundreds of near-duplicate names down to a few dozen without losing any real signal.
User properties or event properties?
Event properties describe one occurrence, such as the payment method on an order. User properties describe the person and persist across events, such as plan tier or A/B variant. A/B test assignment is a user property, not an event. Put each fact in one place so you are not maintaining it twice.
How do I stop one person counting as several users?
Never set a user_id before the person logs in, use an identify-and-merge call at login so anonymous activity joins the account, keep the same user_id across devices, and reset it on logout. On the server, include a deduplication id so the same event is not counted twice.
Should the plan live in a spreadsheet or in code?
Either works if it is versioned and enforced. A JSON Schema per event, a Segment Protocols plan or an Avo workspace all qualify, and a schema file in git with a CI check is the free-stack equivalent. A plan nobody validates against drifts within a quarter.
Changelog
1.0.0, 5 November 2026: first release. Use, adapt and share this skill under CC BY 4.0: credit Afeez Adebayo and link to this page.
