Webclat / GTM Practice

Why do I get "dataLayer is not defined" even though the GTM snippet is on the page?

Quick answer

This error means code elsewhere on the page is trying to read or push to dataLayer before the GTM snippet that declares it has actually executed - usually because that other code runs before GTM's inline bootstrap, regardless of where the GTM snippet visually sits in your HTML source.

Why this happens

The standard GTM installation snippet includes a small inline script that does window.dataLayer = window.dataLayer || [] before loading the async container script - that line is what actually creates the array. Any other code that references dataLayer directly will throw exactly this ReferenceError if it executes first, regardless of where the GTM snippet appears to sit in your HTML - load order for async/deferred scripts, dynamically injected scripts, and framework-rendered components does not always match source order.

Fix it

  1. Find every place in your codebase that references dataLayer directly (not through GTM's own tags) and confirm each one runs after the GTM snippet's inline bootstrap line has executed - search for dataLayer.push outside of GTM's own container.
  2. The safest universal fix: never assume dataLayer exists - always declare it defensively before using it: window.dataLayer = window.dataLayer || []; window.dataLayer.push({...}). This is idempotent and eliminates the ordering dependency entirely for your own custom pushes.
  3. If a third-party script is the one throwing the error, check whether it can load after GTM, or wrap its initialization to only call the dataLayer-dependent function after confirming typeof window.dataLayer !== 'undefined'.
  4. If you use a framework integration (a React dataLayer hook or context), confirm it also uses the defensive pattern internally rather than assuming GTM has already initialized it, since component mount order in an SPA is not guaranteed.
  5. Check that the GTM snippet itself has not been partially removed or corrupted - inspect page source for the literal dataLayer = dataLayer || [] line to confirm it is actually present, not just the loader script tag.

How to verify it worked

Open the console on a fresh page load (hard refresh, cache disabled) and confirm no "dataLayer is not defined" error appears; then type window.dataLayer directly into the console and confirm it returns an array, even if empty, rather than undefined. Re-test any interactions that were failing and confirm they now execute without throwing.

Still stuck after working through this?

Send us what you are seeing in Preview and the Network tab. We trace GTM containers for a living and can usually tell you what is actually happening in one look.

Ask a GTM Engineer