quest_ga4_data_layer_mistakes.exe
_
×

The GA4 Data Layer: 7 Mistakes That Wreck Your Data (and How to Fix Them in 2026)

The GA4 data layer is the foundation of your GTM tracking. Here are the 7 mistakes that inflate or break your data, with the right code and a 2026 checklist.

ga4 gtm datalayer ecommerce guide

The GA4 data layer is the invisible foundation of your entire tracking setup: it is the JavaScript object where your site drops the information (page view, add to cart, purchase) that Google Tag Manager then reads to feed GA4. When it is clean, your reports are reliable and your campaigns run on real signal. When it drifts, the damage is sneaky: revenue inflated two to four times over, empty product reports, a missing transaction_id that double-counts your sales. According to measurements gathered in 2026, close to 70% of e-commerce implementations ship at least one critical data layer error. This guide is grounded in practice: what a clean data layer actually is, the 7 most common mistakes with the right code to push, and a validation checklist so nothing breaks again when the site evolves.

What a clean data layer is

Before the mistakes, let us set the frame. The data layer is a plain JavaScript array, declared on the page before GTM loads:

window.dataLayer = window.dataLayer || [];

You never rewrite that array, you push objects into it as interactions happen:

window.dataLayer.push({
  event: "add_to_cart",
  ecommerce: {
    currency: "EUR",
    value: 29.90,
    items: [{
      item_id: "SKU_12345",
      item_name: "Organic cotton t-shirt",
      price: 29.90,
      quantity: 1
    }]
  }
});

Three principles hold the whole structure together. First, the variable name is case-sensitive: it is dataLayer, never datalayer or DataLayer. One letter out of place and GTM reads nothing. Second, you push, you do not overwrite: dataLayer.push() appends a message, whereas a direct assignment (window.dataLayer = [...]) destroys the history and breaks the triggers already armed. Third, every push follows a stable event schema: an event key that names the action, and normalized parameters (types, case, units) that GTM will always find in the same place.

Think of the data layer as a data contract between the site and the tag manager. The site commits to providing fields that are consistently named, typed, and formatted; GTM commits to reading them without guessing. The moment one side breaks the contract (a price as text, a lowercase currency, a renamed key), the chain fails silently.

If your GA4 property is new or shaky, fix the foundations first with the guide Set Up GA4 From Scratch, then come back to secure the data layer that feeds it.

The 7 mistakes that wreck your data

1. An empty or malformed items[] array

This is the most visible mistake. Your monetization reports show revenue, yet the “Items purchased” report stays stubbornly empty. The cause: the purchase event (or view_item, add_to_cart) fires with an empty items array, or one filled with objects that do not match the GA4 schema.

GA4 expects a precise structure: items must be an array of objects, each carrying at least item_id or item_name. A singular items object, a string instead of an array, or a numeric item_id instead of a string is enough to empty your product reports.

// Correct
window.dataLayer.push({
  event: "purchase",
  ecommerce: {
    transaction_id: "T_20260617_0042",
    value: 89.70,
    currency: "EUR",
    items: [
      { item_id: "SKU_12345", item_name: "Organic cotton t-shirt", price: 29.90, quantity: 2 },
      { item_id: "SKU_67890", item_name: "Logo cap", price: 29.90, quantity: 1 }
    ]
  }
});

2. A missing or non-unique transaction_id

Without a transaction_id, GA4 cannot deduplicate purchases. As a result, a customer who refreshes the confirmation page triggers a second purchase, and your revenue doubles on the affected orders. Conversely, a hard-coded transaction_id (the same value for every order) overwrites transactions against each other.

The rule is simple: every order must carry a genuinely unique identifier, ideally the order ID from your back office, pushed once on the confirmation page. GA4 uses this field to ignore duplicates received within a given time window.

3. A lowercase or missing currency

The currency field must follow the uppercase ISO 4217 format: EUR, USD, GBP. Push eur in lowercase, or omit the field, and GA4 either rejects the monetary value or applies the property’s default currency. On a multi-currency site, that guarantees wrong revenue: dollars counted as euros, or amounts ignored entirely.

// Wrong: "eur" in lowercase, value as text
ecommerce: { currency: "eur", value: "89.70", items: [/* ... */] }

// Correct: uppercase ISO currency, numeric value
ecommerce: { currency: "EUR", value: 89.70, items: [/* ... */] }

4. Prices and amounts sent as text

GA4 expects numbers for value, price, and quantity, not strings. A price pushed as text ("29.90", or worse "29,90 EUR" with a comma and a symbol) breaks aggregation: GA4 may read the value as zero, or refuse to sum it. The classic symptom is undervalued or zero revenue even though the transaction count looks right.

Before the push, always convert your amounts to decimal numbers using a dot, with no symbol and no thousands separator: parseFloat(price) on the JavaScript side, or clean formatting on the server side. The decimal separator is the dot, never the comma.

5. Forgetting ecommerce: null between events

This is the most treacherous mistake, because it does not break anything right away. When you push several e-commerce events in a single session (a product view, then an add to cart), the ecommerce object from the first push stays in memory in the data layer. If you do not reset it, the items from the first event bleed into the second, and you end up with phantom products attributed to the wrong events.

The fix is a single cleanup line before each new e-commerce push:

// Reset before pushing the new event
window.dataLayer.push({ ecommerce: null });

window.dataLayer.push({
  event: "add_to_cart",
  ecommerce: { currency: "EUR", value: 29.90, items: [/* ... */] }
});

That ecommerce: null clears the previous object and guarantees each event fires with its own data only.

6. Overly broad triggers that inflate revenue

On the GTM side, a poorly scoped trigger is as destructive as a coding error. The typical case: a purchase tag that fires on “all pages” whose URL contains /confirmation, when that same URL is also the order-tracking page viewed several times after the purchase. Every visit re-counts the sale. You also see tags armed on a custom event that is too generic and fires on every click.

Always scope your triggers to the precise data layer event (event equals purchase), never to a URL pattern alone, and combine it with a condition on the presence of transaction_id. It is this imprecision, more than the code itself, that most often inflates revenue two to four times over.

7. Inconsistent key casing and naming

The last trap is diffuse but common: a site that pushes item_name here, itemName there, or that mixes value, revenue, and total across pages. GTM reads exactly what it was told to read; any variation in the key name returns an undefined value. The symptom is a parameter that shows up on some pages and not others, with no apparent logic.

The solution is not technical but organizational: a data layer specification, written once, that locks the name, type, and format of every key, and that developers and marketers alike respect. This is the heart of the data layer governance that is becoming a standard in 2026.

Mistake, impact, fix: the reference table

MistakeImpact on your dataFix
Empty or malformed items[]Empty product reportsArray of objects with item_id/item_name
Missing or fixed transaction_idDouble-counted or overwritten salesUnique order ID, pushed once
Lowercase or missing currencyWrong or ignored amountsUppercase ISO 4217 code (EUR)
Amounts as textZero or undervalued revenueDecimal numbers with a dot, no symbol
Forgetting ecommerce: nullPhantom products between eventsPush { ecommerce: null } before each event
Overly broad triggersRevenue inflated 2 to 4 timesTrigger on the exact event + transaction_id
Inconsistent casing and namingIntermittently undefined parametersA locked data layer specification

The data layer validation checklist

Fixing is not enough: you have to validate, then revalidate every time the site changes. Here is the sequence to run before any production release.

First, GTM Preview Mode. Open the preview, reproduce the journey (product view, add to cart, purchase), and inspect the Data Layer tab at each step. Check that every expected event appears, exactly once, with its complete ecommerce object.

Next, the schema check. For each event, confirm that items is indeed an array, that currency is uppercase, that value, price, and quantity are numbers, and that transaction_id is present and unique on the purchase.

Also verify consent. Make sure your e-commerce pushes respect the Consent Mode state and do not fire before the user has made a choice. The full mechanics are covered in the guide Consent Mode v2 in GA4.

Test the reset between events: on a page that chains several e-commerce events, confirm that ecommerce: null is pushed and that the items do not blend together. Single page applications (SPAs) deserve special attention, because navigation does not reload the page and the data layer is not reset automatically.

Finally, harden collection on the server side. Routing your events through a server container adds a layer of control and resilience against browser blocking. The full walkthrough is in the guide GTM Server-Side: Why and How to Migrate.

To audit quality over time, nothing beats the raw export. If you have wired up the GA4 BigQuery export, you can query event-level parameters directly and spot transactions with no transaction_id, non-standard currencies, or null values, without relying on interface sampling.

In summary

A reliable data layer is not a matter of luck, it is a data contract honored at every push. The seven mistakes covered here (empty items, missing transaction_id, lowercase currency, amounts as text, forgetting ecommerce: null, overly broad triggers, inconsistent naming) account for nearly every case of inflated revenue and empty reports. The cure comes down to three reflexes:

  1. Lock the schema: a data layer specification that defines the name, type, and format of every key, shared between developers and marketers.
  2. Push cleanly: always dataLayer.push(), always ecommerce: null before each new event, numbers and currencies in the right format.
  3. Validate every time: Preview Mode, schema check, consent, SPA reset, then ongoing BigQuery audits.

The data layer is the building block every other tool assumes. Securing it once means GA4, server-side, and BigQuery finally work on numbers you can trust. To go further on the overall architecture of your measurement, see how to choose your analytics stack in 2026.