All posts
5 min readdatalayer, gtm, ga4, best-practices

DataLayer design: event and parameter names that won't break in six months

Most dataLayer messes start on day one with sloppy naming. A small set of conventions — consistent event names, typed parameters, one push per real-world action — keeps GA4 and every downstream tag readable as your site grows.


A dataLayer breaks for one of two reasons: someone renamed something, or two people invented different names for the same thing. Both are design problems, not engineering problems, and both are solved before any code is written — by deciding your naming rules once, writing them down, and matching Google's recommended events wherever they exist. Here is a convention that survives redesigns, agency handovers, and the fourth developer.

Why naming is the whole game

The dataLayer is a contract between the people who build the site and the people who measure it. Every downstream thing — GTM triggers, GA4 reports, audiences, BigQuery queries, warehouse joins — keys off the strings you choose.

Change a string and everything downstream breaks silently. The tag still exists, the trigger still exists, the condition just never matches. Nothing errors. That is why containers drift rather than fail.

So the goal is not elegance. It is stability: names that nobody has a reason to change in three years.

Rule 1: Use Google's recommended events, exactly

Before inventing a name, check whether GA4 already defines one. If it does, use it — the exact string, with the exact parameters.

  • view_item, add_to_cart, remove_from_cart, view_cart, begin_checkout, add_payment_info, purchase, refund for ecommerce.
  • generate_lead, sign_up, login, search, share for common non-commerce actions.

This is not stylistic. GA4's ecommerce reports, Google Ads conversion imports, and audience builders only recognise those names. A custom order_complete collects data perfectly and populates nothing in the Monetisation reports.

Rule 2: snake_case, always

Lowercase, underscores, no spaces, no camelCase, no hyphens.

GA4's own events use snake_case. Mixing conventions means someone eventually writes addToCart next to add_to_cart, both collect data, and your reports split in half. Case sensitivity is real and unforgiving in every downstream system, especially BigQuery.

Rule 3: Describe what happened, not what should happen next

Name the event after the user action, not the marketing intent.

Good:  add_to_cart, generate_lead, video_complete
Bad:   retarget_user, high_intent_signal, funnel_step_3

Intent changes; behaviour does not. "Funnel step 3" becomes wrong the moment the funnel gains a step, and nobody will remember to rename it.

Rule 4: Never encode values in names

Bad:   purchase_129_usd, view_item_shoes, signup_newsletter_footer
Good:  purchase with value: 129, currency: 'USD'
       view_item with item_category: 'shoes'
       sign_up with method: 'newsletter', location: 'footer'

Encoding values in event names creates unbounded name cardinality, burns through GA4's 300-event-name limit, and makes every report a manual aggregation. Values belong in parameters. Always.

Rule 5: Decide the scope of every field once

Three scopes, three different homes:

ScopeDescribesExampleWhere it goes
EventThis one occurrencemethod, button_idEvent parameter
UserThe person, persistentlymembership_tierUser property
ItemOne product in a listitem_brand, variantInside the items array

Getting this wrong is expensive to fix later, because changing scope means re-registering dimensions and losing comparability with historical data. Custom dimensions without blowing up cardinality covers the reporting consequences.

Rule 6: Keep values bounded and normalised

Parameter values that will become dimensions must be low-cardinality. Register a raw URL, a user ID, a timestamp, or a price-as-string and GA4 collapses your real values into an "(other)" bucket.

Normalise at the source: lowercase category names, a fixed set of method values, currency as an ISO code, booleans as true/false rather than "yes"/"Y"/1.

Rule 7: Push objects, not fragments

Send everything an event needs in one push, so a tag never has to correlate two pushes:

window.dataLayer.push({
  event: 'add_to_cart',
  ecommerce: {
    currency: 'USD',
    value: 49.00,
    items: [{
      item_id: 'SKU-1189',
      item_name: 'Merino Crew',
      item_brand: 'Northlight',
      item_category: 'Knitwear',
      item_variant: 'Navy / M',
      price: 49.00,
      quantity: 1
    }]
  }
});

Two details that cause real bugs: clear or overwrite the ecommerce object between pushes so a previous event's items do not leak into the next one, and make sure window.dataLayer is initialised before GTM loads or early pushes vanish.

Rule 8: Write the tracking plan before the code

A tracking plan is a table with one row per event: name, when it fires, every parameter, each parameter's type, whether it is required, and which platform consumes it.

It takes an afternoon and it is the difference between a schema and a folklore. When a new developer joins, or an agency takes over, or someone asks "do we track that?", the plan answers in seconds. Without it, the answer is "let me check the container", which is how you end up with two names for one action.

What to do with a dataLayer that is already a mess

Do not rename everything at once — you will break every report at the same time.

  1. Document what exists, including the wrong names. You cannot migrate what you have not inventoried.
  2. Add the correct names alongside the old ones. Fire both for a transition period.
  3. Move consumers over — triggers, reports, audiences — one at a time.
  4. Verify parity for a full reporting cycle: the new event should match the old one's volume.
  5. Then remove the old push, and note the date in your reporting annotations.

FAQ

Should I use GA4's recommended event names even if they do not fit my business perfectly?

Yes, where one exists for the underlying action. The reporting and bidding integrations only recognise the exact names, and a near-fit with correct parameters is worth far more than a perfect name with no integration.

What is the difference between an event parameter and a user property?

A parameter describes the occurrence — what was clicked, what it was worth. A user property describes the person and persists across their events. If the value would be the same on every event for that user, it is a user property.

How many events should a site track?

Most sites are well served by fifteen to thirty meaningful events. Hundreds usually means page-level detail is being encoded in names instead of parameters.

Can I rename an event without losing data?

Not retroactively — historical data keeps the old name. Run both names in parallel, migrate consumers, then retire the old one, and annotate the switchover date so future comparisons account for it.

Does the dataLayer have to be initialised before GTM loads?

Yes. If window.dataLayer does not exist when the container loads, pushes made before initialisation are lost silently. Declare it in the same head script, above the container snippet.

Check whether your site initialises a dataLayer at all — the free tracking audit checks that, plus GA4, GTM, and consent signals, on any URL.


See where your tracking stands

Run the same 13-check audit referenced in this post against any URL. No signup, results in seconds.

Run a free audit