How to debug GTM without Preview mode
Preview needs container access, changes the page, and only speaks for one container. Here is how to verify GTM from the requests it actually produces.
Preview mode is the official way to debug Google Tag Manager and it is very good at one specific thing: telling you why a trigger evaluated the way it did. It also has three constraints that come up constantly. It needs edit access to that container. It changes the page it is debugging. And it only knows about tags inside that one container, which is rarely all the tracking on the page.
What Preview mode cannot cover
- A container you do not have access to. A client site before the engagement starts, a handover from another agency, a competitor's implementation, your own site when the GTM account belongs to somebody who left.
- Tags that are not in GTM. A Meta pixel hardcoded in the theme is invisible to Preview, and it is precisely the tag that causes double conversions and consent violations.
- The gap between fired and sent. Preview says the tag fired. A Content Security Policy rule, a content blocker or a network error can still stop the request. "Fired" and "arrived" are two different claims.
- Pages that behave differently under Preview. Preview adds parameters and a debug cookie, and single-page apps, consent banners and bot protection do not always take it well.
The four questions
Debugging a GTM implementation is really four questions in a row, and each one has an answer you can get from the browser:
- Is the container on the page at all? A request for
gtm.jsgives you the container ID. Watch for a site that renamesdataLayer— the snippet's last argument is the name, and if it is notdataLayerthen every guide you read about typingdataLayerin the console is wrong for that site. - Did the dataLayer receive the event? The push either happened or it did not, and this is a question about the site's own code, not about GTM.
- Did a tag fire for it? The published container is a public file. Parsing it answers "is there even a tag listening for this event", which is a surprisingly common answer to "why is nothing happening".
- Did the request leave, and carrying what? This is the only one that proves anything reached the vendor.
Reading the container without Preview
gtm.js is served publicly to every visitor, so the published container can be read from the
container ID alone: the tags in it, the triggers, and which events those triggers listen for. That turns
"the developer says there is a purchase tag" into something you can check.
The honest limits: you see the published version, not the workspace, so unpublished changes are invisible. You see that a trigger exists, not why it evaluated true on this particular page load. The second one is exactly what Preview mode is for, and it is why Preview keeps its place in the toolkit.
The dataLayer, and its two traps
Timing. Anything that reads dataLayer after the page has loaded sees an array
that GTM has already processed and rewritten. Pushes that happened during load — consent defaults, the very
first gtm.js event, ecommerce impressions fired inline — can be gone by the time you look. A
monitor that hooks the array before the page script runs sees the whole history; a console snapshot does
not.
Fragility. Anything that overrides push to watch it is standing in the middle
of the site's own code, and doing it carelessly breaks the page. A push containing a circular structure, a
DOM node, or a value that cannot be cloned has to survive intact and reach GTM unchanged. If your debugging
tool changes the behaviour of the thing being debugged, everything after that is noise.
From push to request
The useful view is not the pushes and the requests separately, but each push next to the requests it
caused. Two things make that harder than it sounds. Platforms spell the same event differently —
purchase in GA4, Purchase for Meta, CompletePayment for TikTok — so
matching has to know the vocabulary. And GA4 batches, so a hit can appear well after the push that caused
it, and after unrelated later hits.
Tag Master links every dataLayer push to the requests it produced, reads the published container so you can see whether a tag exists for an event, and turns a captured push into a ready GTM recipe: the trigger condition and the Data Layer Variable names to create.
When a tag fires and nothing arrives
This is the case Preview mode reports as a success. Worth checking, in order:
- Content Security Policy. The page refuses to load the vendor's script or refuses to connect to its endpoint. The console says so, briefly, once.
- Consent gating. The tag fired, the consent state said denied, and the vendor's own script declined to send.
- Unload timing. A tag firing on link click or form submit races the navigation. Without
sendBeaconthe request is cancelled mid-flight and nothing is recorded anywhere. - A blocker. Yours, or the visitor's. Easy to forget when debugging on your own browser.
Building the trigger you actually need
Most GTM work is not debugging, it is the same small task repeated: something on the page needs to become an event. Clicking the element and getting back a stable CSS selector, a trigger condition and a variable that extracts the value is the difference between five minutes and half an hour — particularly on sites whose class names are generated and change on every deploy.
When Preview mode is still right
When the question is why. Why did this trigger fire on a page where it should not have. Which variable was empty at the moment the tag ran. What the lookup table returned. Preview is the only thing that can see inside GTM's own evaluation, and no amount of request reading substitutes for it. Use the requests to find out that something is wrong and where; use Preview to find out why.
Related guides
- Test Events for TikTok, Snap, UET and five more
- Testing tracking without polluting production analytics
- A GTM click trigger the next deploy will not break
Try it on your own site
Tag Master is free, needs no account, and collects no data.
Add to Chrome — Free