Tag Debugging

Live Tag Debugging for GA4 and GTM

Published 

One person pointing at something on a laptop screen while another types

There are three ways to debug analytics, and most people only use the first two.

GTM Preview mode shows you what GTM decided. Which triggers matched, which tags fired, what each variable resolved to at that moment. It is excellent for answering "why did this tag not fire?" and it is the right first stop for trigger logic.

GA4 DebugView shows you what Google received and processed. It is lagged, it requires debug mode, and it shows a cleaned-up version of reality.

Watching the actual network requests shows you what left the browser. This is the ground truth, and it is the only one of the three that will tell you a hit fired twice, that a parameter arrived as a string when it should have been numeric, or that the consent state on the wire does not match what the banner said.

You need all three, and you need to know which one answers which question. Here is a workflow that uses them in the right order.

When each tool is the right tool

Use GTM Preview when the question is "why did/didn't this fire?" The tag summary and the variable resolution at each event is the fastest path to a trigger bug. If a Click trigger is not matching, Preview shows you the click element and the conditions it failed.

Use DebugView when the question is "did GA4 accept this?" Particularly for confirming that a key event registered, or that a parameter's value survived processing. DebugView also shows you user properties, which are easy to miss on the wire.

Watch the network when the question is "what actually happened?" Duplicates, parameter types, consent state, client ID stability, request timing, ordering. None of these are reliably visible in the other two.

The trap is using Preview alone. Preview will happily show you one page_view tag firing once — and be entirely correct — while a hard-coded gtag.js snippet elsewhere on the page fires a second one that GTM knows nothing about. Preview only sees GTM. The network sees everything.

Preview mode changes the page. Debug mode adds a _dbg parameter, opens a debug channel, and in some setups changes which triggers fire. If a bug appears only outside Preview mode, believe it — that is a real class of bug, and network capture is the only way to investigate it.

The workflow

1. Reproduce with capture running before you interact

Start capture, then load the page. Hits fire during initial load — the config hit, the first page_view, consent defaults — and if you start capturing after the page has settled you miss the most informative part of the sequence.

2. Read the load sequence in order

The order tells you as much as the content:

  1. Consent default should be established first.
  2. The GA4 configuration hit.
  3. page_view.
  4. Anything Enhanced Measurement contributes.

A page_view arriving before the consent default is a timing bug, and it is the standard failure mode of a Consent Mode v2 implementation whose default is on the wrong trigger.

3. Check for duplicates immediately

Two hits with the same event name and the same _p value are the same page load firing twice. This is the most common data-quality bug in GA4 and it takes five seconds to spot. The payload reference covers _p and the other identity parameters.

Usual causes, in order of frequency:

  • A hard-coded gtag.js snippet plus a GTM configuration tag.
  • Enhanced Measurement plus a hand-built GTM tag for the same interaction — outbound clicks, file downloads, scroll, site search, video.
  • A trigger that matches on both a click and a form submit for the same action.
  • Two GTM containers on the page, usually a legacy one nobody removed.

4. Walk the journey, not the page

Load a page and you verify a page_view. Walk a purchase journey and you verify the sequence: view_itemadd_to_cartbegin_checkoutadd_payment_infopurchase. Sequence bugs — an event that fires on the wrong step, or fires twice because the user navigated back — only appear when you walk it.

This is also where session-identity bugs surface. Check that cid and sid are stable across the whole journey. A new sid mid-funnel means the session restarted, which usually means cross-domain tracking broke at the payment gateway.

5. Check parameters against the spec, and types against the payload

For each event, confirm every parameter you expect is present and correctly typed. epn.value=49.99 is a number. ep.value=49.99 is a string, and it will not aggregate as a metric.

Then remember that presence on the wire is not sufficiency — an unregistered parameter is collected and permanently invisible. That is a separate check; see custom dimensions vs event parameters.

6. Verify the consent state on each hit

gcs=G111 means both storage types granted. gcs=G100 means both denied. If you declined consent and see G111, the gate is not working regardless of what the CMP interface reports.

7. Check for PII

Look at dl (document location). An email address in a query string is a policy violation and, once it is in GA4, a deletion request rather than a code fix.

Debugging what you cannot see in devtools

Three situations where the browser network tab is not available or not enough.

Mobile web. Remote debugging via chrome://inspect works but is fiddly and requires a cable. A capture that runs server-side and reports back is considerably easier.

Someone else's browser. A bug that reproduces only for a colleague on a different device or network. Asking them to open devtools and screenshot the network tab is a poor experience and usually produces the wrong screenshot.

A journey behind authentication that you need to check repeatedly. Doing it once is fine. Doing it every Tuesday forever is where manual QA stops being realistic.

The third case is the one that matters most, because it is the one that determines whether tracking stays correct. Which brings us to the actual point.

Debugging once is not the goal

Here is the pattern every analytics team eventually recognises.

You debug a checkout flow thoroughly. Everything is correct. You sign it off. Four months later a front-end refactor changes a button's class name, the click trigger stops matching, and add_to_cart silently stops firing. Nobody notices until someone builds a funnel report in the next quarterly review and finds a gap.

The debugging was correct. The problem is that it was a point-in-time verification of something that changes continuously.

The fix is to make the verification repeatable. Record the journey once — the steps, the clicks, the form fills — and record what should happen: add_to_cart must fire, with value greater than zero and currency equal to GBP. Then have that journey replayed automatically on a schedule, in a real browser, with the same assertions checked every time. When an assertion fails, someone gets an email that day rather than in the next quarterly review.

That converts analytics QA from something that happens when someone remembers into something that happens whether or not anyone remembers. Analytics regression testing is the same idea applied to the numbers rather than the journeys — the two are complementary, because synthetic replays catch what you thought to assert and statistical monitoring catches what you did not.

How Tagfire helps

Tag Debugger does the capture side. Hits are decoded and grouped as you browse — event name, every parameter, consent state, client and session IDs — with no devtools and no manual gcs parsing. Duplicate hits are flagged. You can run it two ways:

  • Browser extension, attached to your own Chrome session, for debugging a real journey on your real machine with your real logins.
  • In-app headless browser, which drives a Chromium instance server-side and streams the hits back. This is how you debug a mobile viewport, a site you cannot install an extension on, or a journey you want a colleague to be able to reproduce from a link.

Both feed the same view, so the workflow does not change between them.

Recordings and monitors are the repeatable half. Record a journey as steps, attach expectations (a purchase event with value > 0 and currency = USD), group several recordings into a monitor for one site, and set a schedule. Every run replays the journeys headlessly, checks the expectations, takes a full-page screenshot, and pixel-diffs it against an accepted baseline. Any failure — a missing event, a failed parameter condition, a step that could not complete, or a visual diff past your threshold — sends one digest email to the recipients you nominate.

Replays send a distinctive user agent so the synthetic traffic can be filtered out of the property they hit, which matters when the site is a client's rather than your own.

Payload Decoder is the no-account version for a single hit: paste a request, get every parameter explained.

The live debugger documentation covers capture, and journeys and monitors covers recording and scheduling.

Related reading
A code editor open on a laptop in a darkened room
GA4

GA4 Ecommerce Tracking with the dataLayer

The full GA4 ecommerce event sequence with working dataLayer examples — view_item_list through purchase, the items array, and the mistakes that break revenue reporting.

Read article