Google Tag Manager Data Layer: Syntax, Variables and GA4 Ecommerce

Google Tag Manager Data Layer: Syntax, Variables and GA4 Ecommerce

analyticsOctober 12, 2026
By Antonio Fernandez

TL;DR

  • A dataLayer.push without an event key only stores values; adding event makes Google Tag Manager evaluate triggers, and a Custom Event trigger fires on that event name.
  • Data Layer Variable version 2, the default in GTM, reads nested keys with dot notation such as ecommerce.transaction_id.
  • Google's GA4 purchase event requires transaction_id, needs currency (for example THB) whenever value is set, and each item needs item_id or item_name.
  • Google's ecommerce examples push ecommerce: null before each ecommerce event so leftover keys from earlier events do not carry into the next one.

The Google Tag Manager data layer is a JavaScript array, named dataLayer by default, that your website uses to hand structured information to Tag Manager: what page this is, who is logged in, what was added to the cart, what was just purchased. Tags then read those values through data layer variables, and data layer events fire triggers, so measurement no longer depends on scraping text or CSS classes from the page.

This guide covers what the data layer is, the dataLayer.push syntax and its event key, how data layer variables work in GTM, the ecommerce data layer that GA4 purchase events need, how pushes fire triggers, how to debug in Preview mode, the mistakes that break it most often, and who should own it.

What the data layer is

When the Google Tag Manager container snippet loads, it looks for a global array called window.dataLayer. Anything your site pushes into that array is processed by Tag Manager in order. Tag Manager keeps an internal data model built from every push: each new object is merged into that model, so a value pushed earlier stays available to later tags until something overwrites it.

The point of the layer is separation. The website knows facts (the order ID, the product SKU, the customer's membership tier) and writes them into the data layer in an agreed format. Tag Manager reads them and decides which tags receive them. A redesign that changes button classes or page text does not break tracking, because the tags never depended on those details.

The array must exist before the container snippet runs if you want to pass values at page load. The standard pattern is to declare it defensively above the GTM snippet:

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

That line creates the array if it does not exist yet and leaves it alone if another script already created it. Writing dataLayer = [] later on the page is a classic bug: it replaces the array and can disconnect it from Tag Manager.

dataLayer.push syntax and event keys

You add information with dataLayer.push(), passing one object of key-value pairs. A page-level push might look like this:

dataLayer.push({ pageType: 'product', userStatus: 'logged_in', language: 'th' });

That push only stores values. Nothing fires because of it. To tell Tag Manager that something happened, include the reserved key event:

dataLayer.push({ event: 'newsletter_signup', formLocation: 'footer' });

The value of event is the name a Custom Event trigger listens for. Everything else in the object becomes available to tags that fire on that event and to later events, because of the merge behaviour described above.

A few rules keep pushes predictable:

  • Key names are case-sensitive. formLocation and formlocation are different keys, and a variable configured for one will return undefined for the other.
  • Use one naming convention across the whole site, either camelCase or snake_case, and write it down.
  • Keep event names stable. Renaming add_to_basket to add_to_cart without updating triggers stops the tags silently.
  • Push after the information exists. Pushing an order total before the backend confirms the order records revenue that may never arrive.

Data layer variables in GTM

Tags do not read the data layer directly. You create a variable in Tag Manager of the type Data Layer Variable, enter the key name, and then use that variable in tags and triggers as {{Variable Name}}.

The Data Layer Variable type has a version setting. Version 2, the default, supports dot notation for nested values. If a push contains ecommerce: { transaction_id: 'T1001', value: 1250 }, a variable with the key name ecommerce.transaction_id returns T1001. Version 1 treats dots as part of the key name, so ecommerce.transaction_id would be read as one literal key rather than a nested value.

Keys from an earlier push stay in the merged model until something overwrites them, which is the root of several ecommerce bugs and is why Google's ecommerce examples clear the ecommerce object before each new event.

You can set a default value on the variable for cases where the key was never pushed. That is useful for flagging gaps in reports, for example a default of "not_set" for a content group that developers forgot on some templates.

The ecommerce data layer for GA4 purchase events

GA4 recommends a set of ecommerce events with fixed names and parameters, including view_item, add_to_cart, begin_checkout and purchase. When the site pushes those events in the expected format, a GA4 event tag in Tag Manager can send the ecommerce data with the "Send Ecommerce data" option using the data layer as its source, rather than mapping every field by hand.

A purchase push sits on the order confirmation page or fires when the payment is confirmed:

dataLayer.push({ ecommerce: null });

dataLayer.push({ event: 'purchase', ecommerce: { transaction_id: 'T1001', value: 1200.00, currency: 'THB', shipping: 50.00, items: [{ item_id: 'SKU_123', item_name: 'Cotton shirt', price: 600.00, quantity: 2 }] } });

The values in that example are illustrative. The rules behind it come from Google's GA4 ecommerce documentation:

  • transaction_id is required for purchase and is what GA4 uses to deduplicate repeated purchase events with the same ID.
  • currency must be sent when value is set, using a three-letter ISO 4217 code such as THB. Without it, revenue metrics are not calculated correctly.
  • items is an array of products, each needing at least item_id or item_name.
  • value should be a number, not a string with a currency symbol or thousands separator.

The first line, pushing ecommerce as null, clears the previous ecommerce object. Because of the merge behaviour, skipping it can let keys left over from an earlier ecommerce event, such as a coupon or list name, carry into the purchase event.

The table below maps common ecommerce moments to the GA4 event name and the keys that matter most.

The ecommerce data layer for GA4 purchase events
Shopper actionGA4 event nameKeys to check first
Views a product pageview_itemcurrency, value, items[].item_id
Adds a product to the cartadd_to_cartcurrency, value, items[].quantity
Starts checkoutbegin_checkoutcurrency, value, items
Completes paymentpurchasetransaction_id, currency, value, items

How data layer events fire triggers

Tag Manager evaluates triggers each time something is pushed with an event key. Its own built-in events follow the same pattern: gtm.js marks container load (shown in Preview as Container Loaded), gtm.dom marks DOM Ready, and gtm.load marks Window Loaded. Clicks, form submissions and scroll depth are pushed as gtm.click, gtm.formSubmit and so on by the built-in listeners.

Your own events work through the Custom Event trigger. Set the event name to purchase and the trigger fires on every push where event equals purchase. The trigger can match with a regular expression, for example a pattern covering add_to_cart and remove_from_cart, and it can add conditions such as "pageType equals product", which reads a data layer variable at the moment of the event.

Timing matters. A variable only holds the values present at the time of the event being processed. If a page pushes event: 'purchase' and then pushes the order data in a second call, tags on the purchase event will not see the order data. Put the event key in the same push as the data it describes.

Debugging in Preview mode

Tag Manager's Preview mode opens Tag Assistant connected to your site. The left-hand timeline lists every message the data layer processed, in order. Selecting one shows four tabs that answer most questions:

  • Tags: which tags fired and which did not on that event.
  • Variables: the value of every variable at that moment, which is where you catch a misspelt key returning undefined.
  • Data Layer: the exact object that was pushed and the merged data model afterwards.
  • Errors: tag-level errors reported by templates.

For GA4 specifically, pair Preview mode with DebugView in GA4, which shows events arriving from the debugging browser in near real time, including the item parameters on a purchase. Test a full journey, from product view to purchase, in a staging environment with a test payment method so the confirmation page actually renders.

Common data layer mistakes

  • Overwriting the array. A later dataLayer = [] or a plugin that redefines it disconnects pushes from Tag Manager.
  • Pushing after navigation. A push placed on a button click that immediately loads a new page may never be processed. Push on the next page or use a beacon-based tag.
  • Purchase fires on every reload. If the confirmation page pushes purchase each time it loads, a refresh records another event. GA4 deduplicates on transaction_id, but ad platform tags may not, so guard the push in the backend.
  • Strings instead of numbers. value: '1,250 THB' cannot be summed. Send 1250.
  • Personal data in the layer. Pushing plain email addresses or phone numbers into the data layer exposes them to every tag in the container. Google's policies prohibit sending personally identifiable information to GA4. Use hashed values only where a feature such as enhanced conversions requires them, under consent.
  • Mismatched naming. Developers push productID while the variable reads product_id. Agree on a written spec before anyone writes code.

Who writes the data layer, developer or marketer?

Both, with different jobs. The marketer or analyst owns the specification: which events, which keys, which values, which tags depend on them. The developer owns the implementation, because the data layer is written in the site's templates, backend or ecommerce platform, where order totals and product IDs actually live.

A good specification lists, for every event, the event name, the page or action that triggers it, each key with its type and an example value, and the tags that consume it. Many ecommerce platforms and plugins ship a ready-made GA4 data layer. Check what they push in Preview mode before writing a custom one, since a duplicate purchase push from a plugin plus a custom push is a common cause of double-counted revenue.

What this means for Thai marketers

Thai stores often sell in THB but run some campaigns in USD, and the data layer should always carry the currency of the transaction, with GA4 handling conversion to the property's reporting currency. Thai product names in item_name are fine, since GA4 accepts Unicode, but keep item_id as a stable SKU so reports join cleanly across Thai and English versions of the same product. Where checkout runs on a marketplace or a payment page on another domain, the purchase push may never happen on your site at all; in that case, server-side or backend reporting of orders is the only reliable source.

The GA4 setup and migration service includes writing a data layer specification and testing it end to end, and the ecommerce marketing team relies on that data to optimise campaigns. If your ads also run on Google, accurate purchase values flow straight into Google Ads bidding.

FAQ: Google Tag Manager data layer

Do I need a data layer to use Google Tag Manager?

No, Tag Manager works without one, but tracking then relies on page elements such as click classes and URLs, which break when the site changes. Any ecommerce or lead-generation site that cares about conversion values should use a data layer.

What is the difference between dataLayer.push with and without an event key?

A push without an event key only stores values in Tag Manager's data model. A push with an event key also tells Tag Manager to evaluate triggers, so tags can fire on it.

Why does my data layer variable show undefined?

The most common reasons are a misspelt or wrongly cased key name, the value being pushed after the event the tag fires on, or a nested key read without dot notation in a version 2 variable. Check the Variables tab in Preview mode at the exact event.

Why should I push ecommerce null before each ecommerce event?

It clears the previous ecommerce object from Tag Manager's merged data model. Without it, items or values from an earlier event can carry into the next one.

Can the data layer contain customer emails?

It should not contain them in plain text. Google's policies prohibit sending personally identifiable information to GA4, and anything in the data layer is readable by every tag in the container.

A clean data layer is the foundation every other measurement improvement sits on. If your GA4 revenue does not match your store's orders, Relevant Audience can audit what your site pushes today and write a specification your developers can build against.

Antonio Fernandez

Antonio Fernandez

Founder and CEO of Relevant Audience. With over 15 years of experience in digital marketing strategy, he leads teams across southeast Asia in delivering exceptional results for clients through performance-focused digital solutions.

Share to:
Copy link:

Read us often? Add Relevant Audience as a preferred source so our articles surface more in your Google results.