Skip to content
Back to blog
GTMJul 10, 2026 · Ludde Nyström · 16 min read

GTM Tag Not Firing? The Complete Diagnostic Checklist (All Causes).

GTM tag not firing? The complete diagnostic checklist — trigger mismatches, paused tags, consent blocking, exceptions — ranked by frequency.

GTM Tag Not Firing? The Complete Diagnostic Checklist (All Causes)

A GTM tag usually isn't firing for one of four reasons: its trigger conditions don't actually match what happened on the page, the tag is paused, a trigger exception is blocking it, or Consent Mode is denying it permission. Those four explain the large majority of "stuck in Tags Not Fired" reports. The rest of this guide covers every other cause — unpublished containers, dataLayer timing, ad blockers, single-page apps, iframes, and GA4-side filters that make a correctly-firing tag look broken — in the order you're most likely to hit them.

Work down the checklist below. Every section tells you exactly what to look for in GTM's Preview mode (Tag Assistant) so you're reading evidence instead of guessing.

The GTM Tag Not-Firing Checklist, Ordered by Frequency

# Cause 10-second check Typical fix
1 Trigger conditions don't match Open the tag under Tags Not Fired — read the red/green condition list Fix the operator or the value being compared
2 Tag is paused Grey "Paused" label next to the tag name in the Tags list Open tag → ⋮ menu → Unpause → publish
3 A trigger exception is blocking it Tag Assistant names the blocking exception directly Narrow or remove the exception trigger
4 Consent Mode is denying it Preview's Consent tab shows the required type as Denied Fix the CMP's update call or the tag's consent requirement
5 Container not published, or wrong environment Workspace version number is higher than Published on the Versions tab Submit → Publish; confirm the right environment/container
6 Fires in Preview, not on the live site Usually #5 — confirm with a hard-refreshed incognito tab Publish, then rule out page-level caching
7 dataLayer isn't populated yet Preview's Data Layer tab shows the push order and payload Push the event after the data actually exists
8 gtm.js itself is blocked No request to googletagmanager.com/gtm.js in the Network tab Fix CSP allowlist; ad-blocker loss isn't fixable client-side
9 No re-fire on SPA route change Preview timeline shows nothing new on client-side navigation Add a History Change trigger, firing option "Once per event"
10 Tag is trapped inside an iframe Preview run against the iframe's own content shows nothing postMessage bridge, or a container inside the iframe
11 It fired — GA4 just isn't showing it Tag Assistant shows Fired but Realtime/DebugView is empty Check Measurement ID and Active data filters, not GTM

1. Is the Trigger Actually Matching What You Think It Matches?

Most common cause, by a wide margin: the trigger you built is stricter, looser, or simply different than the condition you think you set.

GTM's equals operator is an exact, case-sensitive string match — no trimming, no normalization. A few specific ways this silently breaks a trigger:

  • Page URL vs. Page Path. Page URL returns the full address including the query string — https://example.com/thank-you?order=123. Page Path strips the query string and returns only /thank-you. If a trigger uses "Page URL equals https://example.com/thank-you" and the real URL carries a query string, it will never match. Page Path is more resilient for path-only matching — but it's still exact, so a trailing-slash mismatch (/thank-you vs. /thank-you/) breaks it too.
  • Click Classes on multi-class elements. If a button has class="btn btn-primary submit-btn", the Click Classes variable returns the entire attribute string, not one class name. A trigger set to "Click Classes equals submit-btn" will never fire on that element, even though the class is clearly present. Switch to "Click Classes contains submit-btn," or — the more robust fix — use the Click Element variable with a "matches CSS selector" condition (e.g. .submit-btn), which checks the element against a real CSS selector instead of a raw string.
  • Case sensitivity, generally. Submit-Btn and submit-btn are different strings to GTM. If a developer renames a class or a dataLayer key changes casing during a deploy, an "equals" condition that worked yesterday can silently stop matching today with no error anywhere in the chain.

Check it in Preview mode: click the event in the left-hand timeline where the tag should have fired, then click the tag itself under Tags Not Fired. GTM lists every trigger condition with a green check or a red X — it tells you exactly which condition failed and what value it evaluated instead of what you expected. This is the single most underused feature in Tag Assistant; most people read "Tags Not Fired" and start guessing instead of clicking in to see the actual comparison.

2. Is the Tag Paused?

Easy to miss because it looks intentional: a paused tag never fires, under any circumstances, no matter how correct its trigger is.

Tags get paused deliberately — someone testing a replacement, temporarily disabling a noisy pixel, pausing during a migration — and then the container moves on without anyone remembering to unpause it. Open Tags in the left nav; a paused tag shows a grey "Paused" label next to its name.

Check it in Preview mode: a paused tag still appears under Tags Not Fired in the debug panel, with an explicit paused indicator. Tag Assistant doesn't bother evaluating its trigger conditions, because the pause overrides them regardless of outcome.

Fix: open the tag, click the three-dot menu in the top right, and select Unpause (or click Unpause directly below Save inside the tag editor). Then — the step people skip — Submit and Publish. Unpausing only changes your workspace; the live container keeps running the paused version until you publish.

3. Is a Trigger Exception Blocking It?

The one that looks like a mystery: the firing trigger's conditions are correct, the tag isn't paused, and it still won't fire.

A trigger exception — GTM calls it a "blocking trigger" — sits alongside a tag's firing trigger and can veto it. If a tag fires on All Pages but has an exception set to Page URL contains /checkout, it will never fire on any checkout page, no matter how correctly the firing trigger itself is configured. Exceptions are genuinely useful (excluding a thank-you page from a generic pageview tag, keeping a shared container's tags out of a sandbox section), but they're also easy to leave in place after the reason for adding them stops applying.

One rule catches people out: an exception can only block a firing trigger of the same event type. A Link Click exception cannot block a Page View firing trigger, and vice versa. If your exception "isn't working," check that its trigger type actually matches the thing it's supposed to be blocking.

Check it in Preview mode: open the tag under Tags Not Fired — Tag Assistant names the specific exception trigger that blocked it, distinct from a plain failed-condition trigger. If you see a trigger listed under "Exceptions" in the tag's Triggering section that you don't recognize, or that came from a template, that's your answer.

4. Is Consent Mode Blocking the Tag?

Increasingly the cause since Consent Mode v2 became mandatory for EU/EEA advertising traffic: a tag can have a perfect trigger and still never fire if the visitor hasn't granted the consent type it requires.

Two separate places consent can block a tag:

  • The tag's own consent setting. Open the tag → Advanced Settings → Consent Settings. If it's set to "Require additional consent for tag to fire" with a type listed (commonly analytics_storage or ad_storage), the tag sits in Tags Not Fired until that type reads "granted" — even if every trigger condition passed.
  • The container-wide default. If your Consent Initialization default is stuck denied — because the CMP's update call never fires, fires too late, or the banner script failed to load — every consent-gated tag stays blocked for the whole session, not just the one you're debugging.

Check it in Preview mode: the debug panel has a dedicated Consent tab. Click through your test session and confirm the on-page default and any subsequent update call show the consent types you expect as "Granted," not "Denied." You can also open DevTools → Network, find a request to google-analytics.com/g/collect, and read the gcs parameter directly: gcs=G111 means both analytics and ad storage are granted, gcs=G100 means both are denied.

5. Is the Container Published — And Are You Looking at the Right Environment?

The most common reason a tag "just stopped working" with no configuration change to blame.

Three variations of the same underlying problem:

  • Unpublished workspace. Every change in GTM lives in a draft workspace until you click Submit and then Publish. Compare the "Workspace" version number in the top bar to the "Published" version on the Versions tab — if the workspace number is higher, you have unpublished changes sitting there.
  • Wrong environment. GTM's Environments feature (Admin → Environments) lets a staging or QA snippet point at a specific container version with its own authentication token, separate from the "Live" environment that always tracks whatever was last published. It's common to confirm a tag against a custom test environment and then assume it's live — check which snippet is actually installed on the URL you're testing.
  • A different container entirely. On sites where staging and production were set up by different people at different times, it's not rare for the two to be running two different GTM container IDs (GTM-XXXXXXX). A tag built in one container will never appear on a site running the other, published or not.

Check it in Preview mode: the debug panel's top bar shows the container ID it's connected to — confirm it matches the container you're actually editing. Then check the Versions tab for the workspace-vs-published gap above.

6. It Fires in Preview, But Not on the Live Site — Why?

This symptom is worth naming on its own because it rules out almost everything above. If Preview mode clearly shows your tag firing — trigger matched, not paused, no exception, consent granted — the problem isn't the tag's configuration. It's one of three things: you haven't published yet (see #5), a CDN or browser cache is serving visitors an HTML snapshot from before your change, or you're comparing two different URLs — a www vs. non-www variant, a staging hostname vs. production — without realizing it.

Google doesn't publish a guaranteed propagation time for a new container version, and in most cases changes are live within a few minutes of publishing. The more common delay is page-level caching — a reverse proxy, Cloudflare, or a service worker serving a cached copy of the HTML itself. Test with a hard refresh in an incognito window, not just a normal reload, before concluding the publish didn't take.

This symptom class overlaps with a separate set of causes specific to the Preview connection itself — a browser extension blocking Tag Assistant, a pop-up blocker, a URL/hostname mismatch between what you typed into the preview prompt and where your snippet is installed, or Shopify's checkout sandbox rejecting a raw GTM container. Our GTM Preview Mode troubleshooting guide covers those specifically — read it if the debug panel itself is behaving strangely, rather than the tag simply not appearing on the live site.

7. Is the Tag Firing Before Its Data Exists?

A race condition, not a configuration error — everything about the trigger and the tag is correct, it just runs too early.

If a tag reads a variable from the dataLayer — a transaction value, an items array, a user ID — and the event that fires the trigger is pushed before that variable exists, the tag fires with undefined and either fails outright or fires with broken data. This is common when a value loads asynchronously — a price fetched from an API, a cart total calculated client-side after render — and the tracking event is pushed on page load instead of waiting for the async data to resolve.

Check it in Preview mode: click the event in the timeline and open the Data Layer tab. You'll see every dataLayer.push() in the order it actually happened, with the full payload of each. If your tracking event fired before the variable your tag depends on was pushed, you'll see it plainly — the variable simply isn't in the dataLayer state yet at that point in the timeline.

The fix belongs in the site's code, not in GTM: push the tracking event only once the data it depends on is confirmed available, ideally as a single dedicated custom event rather than reusing a generic page-load event and hoping the timing works out. See our dataLayer best practices guide for the correct push structure.

8. Is gtm.js Itself Being Blocked?

When nothing in the container fires — not one tag, ever — for a specific visitor.

Two separate mechanisms can stop gtm.js from ever loading, which takes every tag in the container down with it, not just the one you're debugging:

  • Ad blockers and privacy extensions. Filter lists like EasyPrivacy specifically target googletagmanager.com. uBlock Origin, Ghostery, and AdGuard block the core gtm.js request with their default lists, which means the entire container never initializes for those visitors — not just your analytics tag, every tag inside it. AdBlock Plus's default list is more permissive and often lets it through, which is why the same site can look "fine" to one tester and completely dark to another. This isn't something you fix client-side — it's a real, permanent gap in your data, and it's the specific reason server-side tagging exists.
  • Content Security Policy. If the site's CSP script-src directive doesn't allowlist *.googletagmanager.com, the browser refuses to load gtm.js outright — on every visitor, every session, not just yours. This is common right after a security review tightens CSP headers without re-testing the tracking stack.

Check it: open DevTools → Network on a plain page load (no Preview mode needed) and search for gtm.js. If there's no request at all, check the Console for a CSP violation ("Refused to load the script... violates the following Content Security Policy directive") before assuming it's an extension. Then retest in an incognito window with extensions disabled to isolate the two.

9. Does It Need to Fire on a Route Change, Not Just a Page Load?

Specific to single-page apps and any site with client-side routing (React, Vue, a headless storefront) — the tag works perfectly on the first page load and then never fires again.

GTM's Initialization and Page View triggers fire once, on the initial page load. A route change inside a single-page app doesn't reload the page, so neither of those ever fires again. If your tag is only wired to a Page View trigger, it works for whoever lands directly on that URL and never fires again for anyone who navigates there through a client-side route change.

The fix is a History Change trigger, which listens for URL fragment changes and the History API's pushState. Two things trip people up when adding one:

  • Firing options. A tag set to fire "Once per page" still only fires once per full page load — a History Change trigger won't override that. Change the tag's firing option to "Once per event" (or "Unlimited") if it needs to fire again on every virtual pageview.
  • Duplicate history events. Some frameworks push multiple history-change events for a single user navigation — a hash change and a pushState firing together, for instance — which fires the trigger, and your tag, more than once per actual page change. If you see doubled virtual pageviews, add a condition on History Source equals pushState (or whichever single source your framework actually uses) to collapse it back to one fire per navigation.

Check it in Preview mode: navigate the SPA the way a real user would — click through routes, don't just reload — and watch the timeline. If nothing new appears when the URL changes, no History Change trigger is wired up at all. If multiple identical-looking events appear for one navigation, that's the duplicate-source issue above.

10. Is the Tag Trapped Inside an Iframe?

Applies to embedded checkouts, embedded forms, and any content served from a different domain inside an iframe on your page.

The browser's Same-Origin Policy stops your site's GTM container from seeing anything that happens inside a cross-origin iframe. If a form, a checkout step, or a widget lives in an iframe served from a different domain, your container — running on the parent page — has no visibility into clicks, submissions, or dataLayer pushes happening inside it, no matter how the trigger is configured. This isn't a GTM bug; it's the same browser security boundary that stops any script from reading another origin's content.

Two ways around it: if you control the iframe's content, install a GTM container inside the iframe itself (or just a dataLayer push) and use the postMessage API to relay events out to the parent page's dataLayer. If you don't control it — a third-party payment widget, an embedded booking tool — check whether the vendor exposes its own tracking API or webhook instead of trying to observe it from outside.

Check it in Preview mode: Preview mode connects to whatever URL you launch it against. If you start it on your page and interact with the iframe's content, you'll see nothing, because you're debugging the parent page's container, not the iframe's. If the iframe is same-origin and still shows nothing, confirm a GTM snippet is actually installed inside the iframe document itself, not just the parent.

11. Did It Actually Fire — And GA4 Is Just Not Showing It?

The one that isn't a GTM problem at all. If Tag Assistant clearly shows your GA4 tag under "Tags Fired," the trigger matched, and GA4 still shows nothing in Realtime or DebugView, stop debugging GTM — the hit left the browser correctly, and the problem is downstream.

  • Wrong Measurement ID. Confirm the ID in the tag's configuration exactly matches the property you're actually looking at. It's common to have a staging property and a production property with similar names — a tag pointed at the wrong one sends real, valid hits that simply never show up where you're looking.
  • An active data filter. A GA4 internal traffic filter (or any custom data filter) set to "Active" — not "Testing" — permanently excludes matching traffic before it reaches your reports. If you're testing from an office or VPN IP that's been marked internal and the filter is active, your own hits are being correctly dropped, by design.
  • DebugView requires debug mode. DebugView only shows events carrying a debug_mode parameter, turned on automatically by GTM's Preview mode but not present on a normal live-site pageview. If you're checking DebugView outside of an active Preview session, it will look empty even when tracking is working correctly.

This is a genuinely different debugging path than everything above it — you're no longer asking "why didn't GTM fire the tag," you're asking "why doesn't GA4 reflect a hit it definitely received." Our symptom-by-symptom GA4 diagnosis tool picks up exactly at this point.

Catch This Before It Costs You Data

NiceLookingData's GTM audit runs 44 automated checks against your live container — flagging tags with no trigger at all, duplicate or conflicting triggers, staging-URL leakage in trigger conditions, and Consent Mode gaps, before they turn into a "why isn't this firing" investigation. Read-only, never touches your live workspace. Run a free GTM audit →

Debug This in the Right Order

Working through eleven possible causes one at a time is slow. In practice, checking them in this order gets you to the answer fastest, because each step rules out several others at once:

  1. Open Preview mode and find the tag under Tags Not Fired. If it's not paused and shows a specific failed trigger condition, you're done — fix #1, #2, or #3.
  2. If the conditions all show green but it's still not firing, check the Consent tab (#4).
  3. If Preview shows it firing correctly, the problem isn't the tag — check publish status and environment (#5), then rule out caching with a hard-refreshed incognito test on the actual live URL (#6).
  4. If the tag fires but with missing or broken data, check the Data Layer tab for timing (#7).
  5. If Preview mode itself won't connect, or a plain page load shows no gtm.js request in the Network tab, you're looking at a blocker, not a trigger — check extensions and CSP (#8).
  6. If this only affects a single-page app's later navigations, or content sitting inside an iframe, jump straight to #9 or #10.
  7. If GTM shows the tag firing correctly and the data still isn't where you expect it, stop looking in GTM — the problem moved to GA4's configuration (#11).

Frequently Asked Questions

Why does my tag fire in Preview mode but not on the live site?

Preview mode reads your workspace draft, not the published container — so it will show a tag firing correctly even if you've never clicked Publish. Compare the "Workspace" version number to the "Published" version on the Versions tab; if the workspace is higher, publish it. If you've already published, the next most likely cause is page-level caching (a CDN, reverse proxy, or service worker serving visitors an older HTML snapshot) rather than anything in GTM — test with a hard refresh in an incognito window before concluding the publish didn't take.

How do I know if a tag isn't firing because of consent?

Two checks. First, open the tag itself → Advanced Settings → Consent Settings, and see whether it's set to "Require additional consent for tag to fire" with a specific consent type listed. Second, open Preview mode's Consent tab and confirm that consent type reads "Granted" at the point in the session where the tag should have fired — not eventually, but before the trigger event happens. You can also inspect the gcs parameter on the network request itself: gcs=G100 means both analytics and ad storage are denied.

Does a paused tag show up in Preview mode?

Yes — it appears under "Tags Not Fired" with an explicit paused indicator, rather than being hidden entirely. Tag Assistant doesn't bother evaluating a paused tag's trigger conditions, because the pause overrides them regardless of outcome. Unpausing a tag only changes your workspace; you still need to Submit and Publish before the change reaches the live site.

What's the difference between "Tags Not Fired" and "Still Running" in the debug panel?

They're different problems. "Tags Not Fired" means the trigger conditions weren't met, the tag is paused, or an exception blocked it — the tag never attempted to run. "Still Running" (or "Failed") means the tag did fire, but Preview mode's tracking of it timed out before it reported success, which often happens with tags that download a script or wait on a network response asynchronously — the tag frequently succeeded in reality even though Preview flags it. If you see "Still Running," verify with the Network tab or a live report rather than trusting Preview's status alone.

Written by
Ludde Nyström — Founder, NiceLookingData

Analytics consultant turned founder. After years running the same GA4 and GTM audits across client engagements, Ludde built the audit into a product — so the pattern-matching takes a minute, not a meeting. More about Ludde →

Free tool

Check your GTM container.

Upload your GTM export or connect live. Our auditor checks 44 best practices and gives you actionable fixes.

Thanks for reading.