A tracking plan is a single document that lists every event you track, when it fires, which parameters it carries, which tools receive it and who owns it. Write it before anyone opens Google Tag Manager, and GA4, your ad platforms and your CRM will count the same actions under the same definitions.
Why you need a tracking plan before touching GTM
Most analytics setups grow one request at a time. Paid media asks for a conversion tag, a developer adds a form event, an agency installs a pixel for a campaign that ended long ago. Eventually the GTM container holds dozens of tags, GA4 shows form_submit, generate_lead and Contact_Form for the same form, and nobody can say which one Google Ads bids on.
Other signs you need a plan: ad platforms optimize toward events nobody has checked in months, a redesign broke a conversion and it took weeks to notice, or only a former agency knows what the tags do.
A tracking plan separates the definition from the implementation. The plan says what an event means and exactly when it fires; GTM, the pixels and the CRM integration are only how it gets delivered. When the two disagree, the plan wins and the tag gets fixed.
Choosing events from business questions, not from what is easy to track
Tracking every click and scroll is easy, and that’s how containers bloat. Start with the questions leadership actually asks, then work down to the events that answer them.
| Business question | Metric | Events needed |
|---|---|---|
| Which channels produce qualified pipeline? | Leads and opportunities by source | generate_lead with source data, CRM stage changes |
| Where do trial users drop off? | Signup-to-activation rate | sign_up, activate_account |
| Are paid social buyers profitable? | New-customer revenue by channel | purchase with customer_type |
Then sort each candidate event into one of three tiers:
- Outcome events: purchases, demo requests, trial signups. These feed ad platforms and board reports.
- Step events: add to cart, begin checkout, book a meeting. These show where the funnel leaks.
- Diagnostic events: form errors, failed payments, zero-result searches. Only for problems you plan to fix.
If an event doesn’t answer a question on the list or diagnose a known problem, leave it out. As a rough guide from the setups I build, a B2B site usually needs 10 to 20 events and an ecommerce store 15 to 25.
Event naming conventions and parameters
Start with GA4 recommended events
GA4 publishes recommended event names, such as generate_lead, sign_up, login, view_item, add_to_cart, begin_checkout and purchase, each with expected parameters. Use them wherever they fit, because some GA4 reports, including the ecommerce reports, only fill in when you do. Invent custom names only for actions GA4 doesn’t cover.
Rules for custom event names
- Lowercase snake_case only. GA4 event names are case-sensitive, so
Request_Demoandrequest_demobecome two separate events. - Match GA4’s verb-first style (
book_meeting,activate_account,subscribe_newsletter) so custom and recommended events read the same way. - Follow GA4’s limits: 40 characters or fewer, starting with a letter, using only letters, numbers and underscores.
- Avoid reserved prefixes such as
ga_,google_andfirebase_. - Put detail in parameters, not in the name. Not
generate_lead_pricing_footer, butgenerate_leadwithform_id: pricing_footerandpage_type: pricing.
Define every parameter
For each parameter, the plan records its name, data type, allowed values and an example. Controlled values matter as much as names: if one form sends form_type: demo and another sends Demo Request, reports split them just like mismatched event names.
Two constraints to plan around. Custom parameters don’t appear in GA4 reports until you register them as custom dimensions, and a standard property can register only a limited number, so register the ones someone will filter by. And never send personal data such as email addresses to GA4; Google’s policies prohibit it. Keep email for the CRM and for the hashed server-side integrations ad platforms offer.
Mapping events to GA4, ad platforms and the CRM
One business action usually carries a different name in each tool. The plan’s destination columns record the mapping, so nobody has to guess later.
| Business action | GA4 | Google Ads | Meta | CRM |
|---|---|---|---|---|
| Demo request | generate_lead | Primary conversion | Lead | Form submission, lifecycle stage set to lead |
| Trial signup | sign_up | Primary conversion | StartTrial | Contact created, trial property set |
| Purchase | purchase | Primary conversion | Purchase | Order recorded, or deal closed-won |
| Add to cart | add_to_cart | Secondary, or not sent | AddToCart | Not sent |
Rules that keep the destinations consistent:
- Few optimization events. Ad platforms should bid on one to three outcome events. In Google Ads, keep step events as secondary conversions so they stay visible without steering bids.
- One value definition. If purchase value excludes tax and shipping in GA4, it excludes them in every ad platform too.
- Deduplication IDs. When an event goes through both a browser pixel and a server-side API, send a shared event ID so the platform can drop the duplicate. For purchases, always pass the order ID as
transaction_id. - Source data at conversion. Forms store UTMs and click IDs in hidden fields so the CRM knows where each lead came from; the UTM naming convention template keeps those values clean.
- Pipeline stages from the CRM. Qualified lead, opportunity and closed-won happen after the website. List them with the CRM as their source, so they can go back to ad platforms as offline conversions.
A tracking plan won’t make every tool report the same totals. Attribution windows, consent and modeling still differ, as covered in why GA4 and your ad platforms never match. What it guarantees is that every tool counts the same action, so the gaps become explainable.
Ownership, QA and change control
Every event gets two named owners: a business owner who uses the data and a technical owner who implements it. One person, usually in marketing ops or analytics, owns the plan itself and approves changes.
QA before publishing
Test each new or changed event in GTM preview mode and GA4 DebugView, and check ad platform events in their own testing tools, such as the test events view in Meta Events Manager. For each event, confirm:
- It fires once per action, not again on page reload or double-click
- It fires on every page and form the plan lists, and nowhere else
- Parameter names and values match the plan exactly
- Value and currency are correct on a real test order or form submission
- When a visitor declines consent, tags behave the way your consent setup says they should
Change control
The plan changes first, then the tags. A request becomes a proposed row, the plan owner approves it, the technical owner builds it in a GTM workspace and names the container version after the plan change, and the status moves to verified only after QA passes. Use fixed status values: proposed, approved, live, verified, deprecated. Deprecated events stay in the plan with a date, so anyone reading an old report knows why a line stops.
The template, with a B2B and an ecommerce example
A shared spreadsheet works for most companies. Use one row per event and these columns:
| Column | What goes in it |
|---|---|
| Event name and description | Exact name as sent to GA4, plus a one-sentence meaning |
| Trigger and pages | The precise condition, such as “demo form submitted and the server confirms success,” and where it can fire |
| Parameters | Name, type, allowed values, example |
| Destinations | GA4, Google Ads, Meta, LinkedIn, CRM, each with its name there |
| Conversion role | Primary, secondary or none, per platform |
| Owners | Business owner and technical owner, as named people |
| Status and last verified | Status value and the date of the last QA pass |
The trigger column prevents the most common bug I find in audits: lead events firing on button click instead of successful submission, so failed validations count as leads.
B2B SaaS example
| Event | Trigger | Key parameters | Sent to |
|---|---|---|---|
generate_lead | Demo form submitted successfully | form_id, page_type | GA4, Google Ads (primary), Meta Lead, LinkedIn, CRM |
sign_up | Trial account created | method, plan | GA4, Google Ads (primary), Meta StartTrial, CRM |
activate_account | User completes the key setup action | days_since_signup | GA4, CRM |
qualify_lead | Sales accepts the lead in the CRM | lead_source | CRM as source, sent to Google Ads and Meta as an offline conversion |
Ecommerce example
| Event | Trigger | Key parameters | Sent to |
|---|---|---|---|
add_to_cart | Cart confirms the item was added | items, value, currency | GA4, Meta AddToCart, Google Ads (secondary) |
begin_checkout | Checkout loads | items, value, coupon | GA4, Meta InitiateCheckout |
purchase | Order confirmed, once per order ID | transaction_id, value, tax, shipping, items, customer_type | GA4, Google Ads (primary), Meta, TikTok, email platform |
subscribe_newsletter | Email capture form submitted | form_id, offer | GA4, email platform |
Keeping the plan current
A plan nobody maintains turns back into guesswork within a few quarters. Build the upkeep into routines you already run:
- Monthly: compare GA4’s event list with the plan. An event in GA4 but not in the plan is a rogue tag; a planned event with zero volume is a broken one. Check that primary conversions in each ad platform move in line with CRM or store numbers.
- Before any launch: new forms, checkout changes, site redesigns and new ad platforms get plan rows before code.
- Quarterly: deprecate events nobody used in a report or decision, and re-verify every primary conversion end to end.
When I take on marketing attribution and tracking work, the tracking plan is the first deliverable, before any tag is touched, because every later fix depends on agreeing what should be counted.
Get it built
If your GTM container grew one request at a time and nobody trusts the conversion numbers, I can audit it, write the tracking plan and rebuild the tags against it. Start with a Growth Audit, $1,500 fixed and credited if we continue. See pricing or get in touch.