One Email Blast, 4,090 Ghost Sessions: an sGTM Blocking-Trigger Gap
A Marketo email blast produced 4,090 unassigned GA4 sessions with (not set) source and zero engagement. The root cause was an empty page_location slipping through a server-side GTM blocking trigger — fixed with one regex update.
The morning after a Marketo email blast, GA4 showed a spike no channel could explain: 4,090 sessions in one day with an Unassigned channel, (not set) source/medium, and zero engagement.
Classic ghost traffic — real clicks that look like bots. This is how I traced it to a single gap in a server-side GTM blocking trigger, and the one-line regex that closed it.
The spike: real users, no identity
Everything about the sessions said “junk”: no source, no channel grouping, no engagement. But the timing said otherwise — the spike aligned exactly with the email send, and the volume tracked the send size. These weren’t bots. They were recipients clicking a real email, and GA4 was recording their arrival with no idea where they came from or what page they landed on.
That combination — legitimate user, empty context — is worth recognizing, because it produces the worst kind of analytics damage. Bot traffic you can filter. Ghost sessions from real users silently distort channel attribution: your email program generated thousands of visits and got credit for none of them, while the Unassigned bucket swallowed the proof.
Root cause: empty page_location slips the blocking trigger
The server-side GTM container had a blocking trigger for malformed hits — the standard hygiene pattern. Its regex checked page_location against known garbage values:
^(chrome-extension://|about:blank)
Here’s the gap. When a lead clicks a Marketo email link, the browser can fire the measurement request with the _ga cookie attached but page_location set to an empty string — "". Not chrome-extension://, not about:blank. Empty.
An empty string doesn’t match ^(chrome-extension://|about:blank), so the hit sails through the blocking trigger, reaches GA4, and becomes a session with no page, no source, and no channel. Multiply by an email blast’s click volume and you get 4,090 ghosts in a day.
The trigger wasn’t wrong about what it blocked. It was wrong about what it didn’t block — the failure mode nobody listed because “empty” doesn’t look like a value.
The fix: one regex update
Old: ^(chrome-extension://|about:blank)
New: ^(chrome-extension://|about:blank|undefined|null)|^\s*$
The additions cover the full family of “no real URL” values:
undefinedandnull— the string forms that serialization produces when the value was never set^\s*$— empty strings and whitespace-only values, which are the exact pattern Marketo email events send
Apply it to the sGTM blocking trigger, publish, and the ghost sessions stop at the server before they ever reach GA4.
Two details worth getting right when you port this:
^\s*$needs to be an alternation at the top level, not inside the parenthesized group — an empty string has no characters for the group’s prefix match to consume- Test with a real email click, not just preview traffic — the empty
page_locationonly reproduces through the actual email → redirect → land sequence
How to audit your own container
If you’re running Marketo (or any email platform) alongside server-side GTM, this gap is worth checking today:
- Segment GA4 for Unassigned sessions with
(not set)source/medium — a persistent baseline of them, spiking on send days, is the signature - Cross-reference spikes against your email send calendar — if ghosts track sends, you have this bug, not a bot problem
- Read your sGTM blocking trigger’s regex and ask what it does with
""— not what it blocks, what it misses - After the fix, watch the Unassigned bucket on the next send — it should stay flat while email-channel sessions rise
The pattern behind the bug
Blocking triggers fail differently than tags. A broken tag shows up as missing data and someone notices. A leaky blocking trigger shows up as extra wrong data, which looks like traffic — and nobody investigates traffic going up.
The general rule: enumerate the empty cases. Every filter that checks a value against known-bad patterns should also decide, explicitly, what happens when the value is empty, whitespace, undefined, or null. Those four are a single regex alternation — and in this case they were worth four thousand sessions a day.
Check your triggers before you blame your data. One regex update, four thousand ghost sessions gone. If you’re running Marketo + sGTM, audit your blocking trigger now.