← blog/gtm-pixel-ga4-false-alarmPT
    // blog/gtm-pixel-ga4-false-alarm.md

    We Added GA4 to a Stack With 3 Tags — and Almost Fell for a False Alarm

    GTM, Pixel and LinkedIn were already running. Verification found a scary 503 — that was just the test tool lying.

    2026-08-19·6 min·tracking·POSTEP Digital

    isolated tag · weak vs strong proof · test outside the building · four tags, zero breakage

    // 00

    Three tags already running, one to add

    Our own site already had three tags running: GTM (with a Google Ads conversion inside it), Meta Pixel, and LinkedIn Insight. The task was simple to describe — add GA4 — and dangerous to get wrong: any misplaced tag can break one of the other three, and then the agency loses real data about its own traffic.

    This post is about the two parts that actually matter in this kind of task: where the new tag goes without touching the others, and how you prove it's really sending data — not just that the code is there.

    // 01

    Where the new tag goes, and where it doesn't

    GA4 could've gone in two ways: as a tag inside the existing GTM container, or hardcoded, alongside the other three. We chose hardcoded — each tag in its own block, visible, without depending on a configuration that lives outside the repository.

    // same pattern as the other three — isolated block, prerender guard
    <!-- Google Analytics (GA4) -->
    <script>
    if (!window.__PRERENDER__) {
    ... injects gtag.js, calls gtag('config', 'G-...')
    }
    </script>
    <!-- End Google Analytics (GA4) -->

    The __PRERENDER__ guard already existed on the other three — the build generates a static version of every page for SEO by running a headless browser, and without that guard, every page generated at build time would become a fake visit in four tools at once. Reusing the pattern instead of inventing a new one is what makes the diff reviewable in 10 seconds.

    Rule: a new tag goes next to the existing ones, never on top. If the diff touches a line from a tag you're not adding, something drifted out of scope.

    // 02

    Verifying isn't “the code is there” — it's “the request went out”

    After deploy, the first check was whether G-XXXXXXXXXX showed up in the production page's HTML. It did. That proves almost nothing — just that the right text ended up in the right file. It doesn't prove anyone's browser loaded the script, or that the event ever reached Google's server.

    // three levels of proof, weakest to strongest
    1. grep the HTML only proves the text exists
    2. script loads (200) proves the browser fetched the file
    3. event is sent proves the data left for Google
    4. shows in the report proves Google received and processed it

    Browser network tab open on the real page: all four scripts loading (200), including — something we didn't even know about — a Google Ads conversion tag already configured inside GTM, firing right along. This far, everything checked out. Zero console errors.

    Rule: “the code has the tag” and “the tag is working” are two different claims. The second one only gets proven by watching the network request go out, or the data show up in the report.

    // 03

    The false alarm: a 503 that wasn't ours

    Except the specific request that sends data to GA4 (google-analytics.com/g/collect) came back 503 — service unavailable. The script loaded, the event was built correctly, but the final send kept failing. First obvious suspicion: we configured something wrong.

    Before touching anything, a quick test: the same kind of request, in the same browser, but on a site we have zero connection to — Google's own site for developers. Result: 503 there too. On their own site. With GA4 configured by Google themselves.

    // isolating the variable — test on something you don't control
    digitalpostep.com → google-analytics.com/g/collect 503
    web.dev (Google's) → google-analytics.com/g/collect 503
    // same error on a site we never configured →
    // the problem can't be in our own config

    If Google's own site, running their own GA4, also gets a 503, the defect isn't in any client's configuration — it's in something about the environment the test ran in. In this case, a tag-debugging browser extension installed in the automation browser, intercepting exactly this kind of call. A diagnostic tool becoming the source of the alarm itself.

    Rule: when a test fails, first ask if the test is trustworthy. Reproducing the failure on a system you don't control is the fastest way to separate “my code broke” from “my test environment is lying to me.”

    // 04

    Summary: four tags, one guard, and a test that saved time

    where it goes

    new tag in its own block, reusing the __PRERENDER__ guard — small diff, easy to review, zero lines touched on the other three.

    weak proof

    the ID's text showing up in the HTML only proves the right file got deployed — it doesn't prove the tag works.

    strong proof

    network tab showing the script load and the event get built and sent — that's the level that actually matters.

    false alarm

    an error reproduced on a site you don't control (the vendor's own) proves the problem is the test environment, not your code.

    // the main rule

    Adding a new tag to a stack that already works isn't about writing the right snippet — it's about proving, with real data going out, that all four keep running together. And when the proof fails, test outside your own building before assuming it's your fault.

    written by
    POSTEP Digital
    ← see all posts