How to Check and Debug the dataLayer in Chrome

All Pixel Helper

How do you check the dataLayer in Chrome?

Open Chrome’s DevTools console on the page and type dataLayer: it lists every object pushed so far, oldest first, and shows new pushes each time you run it again. To see which push fired which Google Tag Manager tag, use Tag Manager’s Preview mode, whose Data Layer tab shows the data after each event.

  1. Open the page, then press Control+Shift+J (Command+Option+J on a Mac) to open DevTools’ Console.
  2. Type dataLayer and press Enter.
  3. Expand the array. Each numbered entry is one push, in the order it arrived.
  4. Do what you’re testing on the page, such as adding to the cart or submitting a form, then run dataLayer again. New pushes appear at the end.

Two shortcuts help on busy pages. dataLayer.filter((entry) => entry.event) lists only the pushes that carry an event, and dataLayer.at(-1) shows the latest one.

Tip: The console runs in the main page by default: its JavaScript Context drop-down starts at top (Console reference). If the tags you’re checking run inside an iframe, pick that frame in the drop-down first.

How do you read what the console shows?

It’s a plain array of everything pushed on this page. Each object is one push; its event key is what Tag Manager’s triggers respond to, and the other keys are data that tags and variables can read. Google calls event a special data layer variable used to fire tags (the data layer, last updated 22 July 2026, checked 25 September 2026).

What else you’ll see:

  • Tag Manager’s own entries. Pushes named gtm.js, gtm.dom and gtm.load come from Tag Manager itself (see the FAQ below).
  • gtag() commands. Google’s snippet defines gtag() as dataLayer.push(arguments) (consent mode guide), so its commands show as Arguments lists such as ['config', 'G-…'] or ['consent', 'default', {…}]. To check the consent commands properly, check that Google Consent Mode is working.
  • Nothing from the last page. The array starts again on every page load. Google’s guide says values you need across pages must be declared in the data layer on each page.

A dataLayer that exists but is empty doesn’t prove Tag Manager is installed. Some debugging extensions create the array themselves, including the viewer described later in this guide, which adds an empty array to every page without a dataLayer. Look for a gtm.js entry, or for the container loading in the Network panel as a gtm.js?id=GTM-… request.

How do you see which push fired which tag?

With Tag Manager’s Preview mode. Google’s steps start from the container you want to edit, and anyone with that access can share a preview link with you. Preview lists each event on the page and shows, for the one you select, whether each tag fired and what triggered it or didn’t (preview and debug containers).

  1. Open your container at tagmanager.google.com.
  2. In the Workspace tab, click Preview. Tag Assistant opens in a new tab.
  3. Enter the page’s address and click Connect. Your site opens in a new window (a new tab if you have Google’s Tag Assistant extension) and shows Connected in the bottom right.
  4. Go back to the Tag Assistant tab and click Continue. The debug interface opens.
  5. Do the action on your site, then select its event in Tag Assistant’s list of events.
  6. Read the tabs for that event:
    • Tags separates the tags that fired on the event from those that didn’t.
    • Variables shows each variable’s resolved value at that event.
    • Data Layer shows what the page pushed for that event and the data layer’s state after it.

Preview is the only tool in this guide that shows why a tag didn’t fire. If you manage the container, start here.

Why isn’t my dataLayer.push working?

Usually because the push goes somewhere Tag Manager isn’t listening, arrives too late, or carries no event. Check the console first: if the push isn’t in dataLayer, the problem is on the page; if it is, the problem is in the container’s triggers or variables, and Preview will show which.

Cause Sign Fix
The array is reassigned, as in dataLayer = [{…}] Earlier entries disappear from the console Initialise the array once, with Google’s line below the table, and use .push() from then on
Wrong case: datalayer.push(…) An error in the console, or pushes Tag Manager never reads Write dataLayer: the name is case-sensitive
The snippet renames the data layer Pushes to dataLayer never reach the container Push to the name the snippet sets, or remove the rename
Values pushed below the container snippet Variables are empty on the first events and fill in later Declare values needed at load above the container code
No event key The data sits in the array but no custom event trigger fires Push the data with an event, such as { event: "sign_up", method: "email" }
An earlier ecommerce push lingers Items or values from one event turn up in the next Push { ecommerce: null } before each ecommerce event
The push runs inside a Shopify custom pixel Nothing new in the storefront’s dataLayer Pick the pixel’s frame in the console; the pushes live in its sandbox

Google’s initialisation line, placed high in the page before the container snippet, is window.dataLayer = window.dataLayer || [];. It keeps whatever is already in the array instead of replacing it.

Sources: Google’s data layer guide for the first four rows and the event key, and its GA4 ecommerce guide (last updated 19 August 2026), whose examples clear the previous ecommerce object before each push. On the last row, Shopify’s custom pixel testing guide says Chrome can show one iframe’s console logs, and its Tag Manager custom pixel tutorial pushes Shopify’s events to window.dataLayer from inside the pixel. What that set-up can and can’t do is in Google Tag Manager in a custom pixel.

How do you turn a dataLayer value into a GTM variable?

With a Data Layer Variable whose name is the dotted path to the value. Google’s help says Version 2 of the variable interprets dots as nested values, so a.b.c reads {a: {b: {c: "value"}}} (user-defined variable types).

Take a purchase push like this one, which clears the previous ecommerce object first, as Google’s examples do:

dataLayer.push({ ecommerce: null });  // Clear the previous ecommerce object
dataLayer.push({
  event: "purchase",
  ecommerce: {
    transaction_id: "T_12345",
    value: 59.98,
    currency: "EUR",
    items: [
      { item_id: "SKU_12345", item_name: "Example T-shirt", price: 29.99, quantity: 2 }
    ]
  }
});

The transaction ID’s path is ecommerce.transaction_id and the value’s is ecommerce.value. For a value inside the items array, a numeric index is widely used: ecommerce.items.0.item_id for the first item’s ID. Google’s help documents the dots, not array indexes, so confirm the result in Preview before you rely on it.

  1. In Tag Manager, click Variables in the left navigation.
  2. In the User-Defined Variables section, click New.
  3. Click Variable Configuration and choose Data Layer Variable.
  4. Enter the path, such as ecommerce.transaction_id, as the data layer variable name.
  5. Check that Version 2 is selected.
  6. Give the variable a descriptive name and click Save.
  7. In Preview, select the purchase event and find the variable on the Variables tab. Its resolved value should be T_12345.

Can you debug Tag Manager without Preview mode?

Partly. When you can’t open the container, or Preview won’t connect, the console shows what the page pushed and Chrome’s Network panel shows what its tags sent, such as GA4’s requests to an address ending in /g/collect. Neither shows triggers or why a tag didn’t fire.

That’s enough to answer “did the page push the right data?” and “did a request go out?”. It isn’t enough to answer “why didn’t this tag fire?”. For that you need Preview: ask someone who manages the container to send a link from Tag Assistant’s Share option. If Preview can’t find your tag, see Google tag not detected. To read each vendor’s requests on the page, see how to check whether a pixel is working.

How do you see each push as a tree and copy its path?

A long dot path is easy to mistype, so a viewer that copies it for you saves a round trip through Preview.

All Pixel Helper, which we build, is a free Chrome extension with a dataLayer tab: a Push Timeline of the pushes to window.dataLayer, newest first. Open a push as a tree, hover a value and click Path to copy its dot-notation path (the tooltip reads “Copy GTM Path: …”), ready for a Data Layer Variable; Val copies a value and JSON an object. Array items come out with numeric indexes, such as ecommerce.items.0.item_id, so check those in Preview as above. Its limits: it watches only a data layer named dataLayer, so a renamed one doesn’t show; gtag() calls appear as rows named “push” with numbered keys (0, 1, 2), so their paths are meaningless; it shows at most 100 pushes a second per frame; and like the console, it shows what was pushed, not which tags fired. It’s the viewer mentioned earlier that adds an empty window.dataLayer to every page without one, and it wraps dataLayer.push to copy each push. The extension itself sends nothing anywhere.

What should an ecommerce push contain?

For a GA4 purchase: the event name purchase, a transaction_id, a numeric value with its currency, and an items array in which each item has an item_id or an item_name. Google marks transaction_id and items as required, and says currency is required whenever you set a value “for revenue metrics to be computed accurately” (GA4 events reference).

The example above has all of them. Other ecommerce events follow the same shape with their own required fields, listed in the same reference. How Shopify stores send the purchase to GA4 is a different path, covered in how Shopify sends purchases to GA4.

Frequently asked questions

Why is dataLayer undefined?

Because nothing on the page created it: there’s no Tag Manager or Google tag, the data layer has another name, or the console is pointed at a different frame. Check the Network panel for the container loading, and the console’s JavaScript Context drop-down. The opposite can mislead too: if a debugging extension created the array, dataLayer exists but holds nothing from the site.

Does Shopify have a dataLayer?

Not by default. Your theme or an app has to push to one, and a theme’s layout applies only to pages outside checkout (Shopify layouts). A custom pixel’s pushes go to a dataLayer inside the pixel’s own frame, not the storefront page’s.

What are gtm.js, gtm.dom and gtm.load?

Tag Manager’s own events. Google’s help names them Container Load (gtm.js, as soon as possible after the page starts loading), DOM Ready (gtm.dom, once the page’s HTML is ready to be parsed) and Window Load (gtm.load, once all initial content has loaded) (Scroll Depth trigger). The container snippet pushes gtm.js itself, so they appear on every page with a container, whether or not the site pushes anything.

All Pixel Helper - Tag, dataLayer & Consent Debugger

All Pixel Helper is a free Chrome extension that lists and decodes the requests a web page sends to 40 ad and analytics platforms, including Meta, TikTok, GA4, Google Tag Manager and Shopify, and marks each one delivered, failed or blocked. It also shows every dataLayer push, with paths you can copy into Tag Manager, and the consent signals on Google, Meta, Microsoft and TikTok requests.

Need help with All Pixel Helper? Email chrome@afixer.app.