The tag that works in preview and nowhere else
Preview is not production with a debugger attached. It is a different session, on a different container state, with different permissions.
A tag that fires in preview and not in production is not mysterious, it is a short list. The version was never published, preview attached to a workspace rather than the live container, your own session behaves differently from a visitor's, a security policy blocks something in one context, an ad blocker is only present in one, consent was granted only in the test, or the server-side preview server is running a different configuration. Each has distinguishing evidence.
Why preview is genuinely a different environment
The instinct is to treat preview as production with instrumentation. It is not, and understanding the differences turns a frustrating hunt into a checklist.
Preview runs against your workspace, which is the editing surface. Google's API overview describes the relationship plainly: a workspace allows multiple concurrent modifications to a container's variables, triggers, folders and tags, and once modifications are made you can create, preview and publish a version. Preview sees the workspace. Visitors see the published version.
Preview also runs in your browser, in your session, with your consent choices, your extensions, your network and your geography. Every one of those is a variable that differs from a visitor's, and each has produced this symptom at least once.
So the question is never why the tag fails in production. It is which of the differences between the two environments is the one that matters here.
The seven causes and how to tell them apart
| Cause | Distinguishing evidence | Fix |
|---|---|---|
| Version never published | The live container's version predates the change | Publish, and check the version history |
| Published a different workspace | Two workspaces both contain edits | Reconcile the workspaces before publishing |
| Security policy blocking | Console shows a policy violation on a visitor session | Add the directive for that product |
| Ad blocker or extension | Fails on a clean profile, works on yours | Confirm and stop optimising for your own browser |
| Consent denied in the real world | Fires when you accept, not when you decline | Check the tag's consent behaviour |
| Trigger depends on debug state | The condition references a debug or preview value | Rewrite the condition |
| Server container running old config | Server preview differs from live tagging server | Redeploy or update the container config |
Work them in that order, because it is roughly the order of frequency and each check is cheaper than the one below it. The first two are settled by looking at a version history, which takes under a minute.
The first two also account for the majority of cases in teams larger than three people, and the second is the nastier one. Two people editing in two workspaces produces a situation where each of them previews their own change successfully and only one of the changes is in the published version.
That is a publishing discipline problem rather than a tagging problem, and the durable answer is small versions published often with a named approver, which is the argument in version control and approvals in a shared container.
The security policy branch
This one deserves its own section because it inverts people's expectations. A content security policy usually breaks preview and leaves production working, since preview requires additional origins that production does not.
But the reverse case exists and it is the one that produces this symptom. Google's guide documents that Custom JavaScript variables will evaluate to undefined in the presence of a policy unless the unsafe-eval directive is given in the script-src section. If your preview session and your production pages are served with different headers, which is common when preview is exercised on a staging environment, the variable resolves in one and not the other.
Undefined rather than an error is what makes this hard. The trigger condition simply stops matching and there is nothing in the console to read.
The same guide notes that Tag Assistant displays the list of resources blocked by your policy under page issues, which is the fastest way to confirm or eliminate this branch. The wider treatment is in running GTM behind a content security policy.
The server-side version of the same symptom
If you run a server container, there is an additional and genuinely separate cause, because preview is a distinct deployment rather than a mode.
Google's manual setup guide states that provisioning the tagging server requires provisioning the server-side tagging cluster and a preview server separately, that you must deploy exactly one preview server and must not configure autoscaling beyond one instance, and that the load balancer or CDN in front of it must have a timeout longer than twenty seconds or preview mode will not work correctly.
Two servers running two container configurations is exactly the setup that produces a container which previews correctly and serves incorrectly. If the tagging servers were deployed before the last configuration change and the preview server after it, the two are running different definitions of the same container.
The server debugger is where you confirm it. It shows which client claimed each request, the incoming request in full, and the outgoing requests each tag generated with the vendor's response, and Google notes the incoming request should be a one-to-one representation of what you see in the browser network tab. If it is not, the discrepancy is between the browser and the server rather than inside the container.
Test as a stranger, not as yourself
The single highest-yield habit here is to stop testing in your own browser profile. Use a fresh profile, no extensions, a different network, and behave like a first-time visitor rather than someone who knows where the button is.
Decline the banner at least once. Most teams accept it every time out of habit, which means the declined path has never been exercised by anybody except real visitors, and that population is not small.
Test the campaign landing pages rather than the home page. Containers get applied through a template that covers the main site and occasionally misses a standalone landing page, and that page is usually the one receiving paid traffic. It is the same conditional failure family described in the GA4 events that break without telling you.
Then repeat after a week of live traffic on real segments. The second pass is where the failures that depend on device, geography or connection speed surface, and it is the reason verification rather than deployment is the actual deliverable of GA4 and Tag Manager implementation.
Turn the diagnosis into a check
Once you have found the cause, write it into a release check so the same investigation does not happen twice. The list is short: is the version published, does a clean profile see the tag fire, does the declined path behave as intended, and does the number match an independent system.
Add a monitor for the case where nobody runs the check. A conversion count that steps down and stays down is the signature of this class of failure, and a machine notices it faster than a monthly report does, which is the argument for automating tracking QA.
Record what the fix was and what the evidence was. Six months later the same symptom will recur with a different cause, and the record is what stops the second investigation starting from zero.
And treat a tracking outage as an outage. It has a start time, a blast radius, a data loss window that cannot be repaired retroactively, and it deserves the same handling as any other production incident, which is the case made in incident management for tracking outages.