Skip to content
Tracking SOP

Debugging Journal

Real, specific, root-caused bugs — not generic troubleshooting tips. 18 entries, presented as Symptom → Root Cause → Fix. Several of these are also distributed to their relevant goal pages.

1

CSP whack-a-mole pattern

Symptom

A newly-added tracking platform’s requests silently fail — no visible error unless DevTools Console is checked directly.

Root Cause

Every new tracking platform (Google Ads native conversion, YouTube’s IFrame API, Meta’s Pixel, the server-side subdomain) requires a corresponding new Content Security Policy allowlist entry — script-src, connect-src, img-src, frame-src — each time. CSP violations block network requests with no obvious error.

Fix

Treat the Consolidated CSP Reference as a starting checklist for any new client site, rather than rediscovering each domain one error at a time.

2

Consent-gated tags that never re-evaluate

Symptom

A tag gated by an Additional Consent Check, triggered only by Initialization - All Pages, never fires — even after the visitor accepts consent.

Root Cause

The tag evaluates exactly once, before consent exists by default, and never gets a second chance once consent is later granted.

Fix

Add a second trigger tied to a custom consent_update event so the tag re-evaluates whenever consent state actually changes. Applied to Microsoft Clarity, LinkedIn Insight Tag, and Meta Pixel Base — all page-load, one-time-evaluation tags.

3

The same fix, wrongly applied

Symptom

Call Click and WhatsApp Click’s Meta tags fired the instant any visitor accepted the cookie banner, with zero actual clicks.

Root Cause

The Consent Update retry-trigger fix from #2 was mistakenly also applied to these tags — which are event-driven (fire fresh on every real click), not page-load tags with a stale-evaluation problem.

Fix

The retry-trigger fix only applies to tags whose sole trigger is a one-time page-load event, never to already-event-driven tags. This exact mistake recurred once more later in the build — see #13.

4

AND vs. OR trigger logic

Symptom

WhatsApp click tracking needed to match either wa.me or web.whatsapp.com URLs — built as a single trigger with two conditions, it silently never fired.

Root Cause

A single trigger with two conditions produces AND logic (both must be true simultaneously) — impossible for one URL to satisfy both.

Fix

The correct GTM pattern for OR logic is two separate single-condition triggers, both attached to the same tag.

5

Variable typed as text instead of selected

Symptom

A Conversion Label value sent garbage data with zero errors thrown.

Root Cause

The value was manually typed into a field as {{Variable Name}} literal text rather than actually selected via GTM’s variable picker — visually identical in some views, but GTM treats it as a literal unresolved string.

Fix

Always select variables via the picker, never type the {{...}} syntax by hand.

6

Enhanced Conversions’ “Include user-provided data” field removed without notice

Symptom

A previously-documented Conversion Tracking tag field for Enhanced Conversions no longer exists in the tag editor.

Root Cause

Google removed this option from the client-side Conversion Tracking tag in April 2025. Official documentation continued describing it as available for some time afterward — cost real debugging time before a recent, dated practitioner report clarified the deprecation.

Fix

The current, correct method is a separate, dedicated Google Ads: User-provided Data Event tag.

7

A known GTM Preview false-negative

Symptom

The native Google Ads Conversion Tracking tag type shows “Failed” in GTM’s own Preview mode.

Root Cause

A documented tendency of this specific tag type to misreport in Preview even when the conversion genuinely succeeds server-side.

Fix

Confirmed via direct network-request inspection that correct data reaches Google’s servers despite the misleading debug label. Don’t chase this specific tag type’s “Failed” status without corroborating evidence from Google Ads’ own side first.

8

A sessionStorage dedup bug affecting every platform simultaneously

Symptom

A second, genuinely distinct lead submitted within the same browser session silently produced zero tracking events across every platform.

Root Cause

The thank-you page’s duplicate-prevention guard used a session-wide boolean flag (“has this browser session tracked any lead, ever”) instead of comparing against the specific lead’s unique token.

Fix

Compare against the specific gate token last tracked, not a blanket boolean — a refresh of the same page still correctly deduplicates; a genuinely new submission (a new token) does not get blocked.

9

Meta’s dataset-creation dialog silently opts into managed Conversions API

Symptom

A duplicate, non-consent-gated CAPI system was found running in parallel to the deliberately-built server-side GTM architecture.

Root Cause

A checkbox (“Add Conversions API for web events to all new and existing datasets”) is checked by default when creating a new Meta Pixel/dataset — this auto-enrolls the Pixel into Meta’s own fully-managed, black-box CAPI system.

Fix

Manually find and disconnect this via the dataset’s own Conversions API settings (Business Settings → Data Sources → Conversions API connection → toggle off Automatically connect + Remove the connection).

10

LinkedIn requires an always-present (even if empty) field

Symptom

LinkedIn’s Conversions API returns a hard 422 error for events with no real identifiers.

Root Cause

user.userIds being omitted entirely from the payload — even when no real identifiers exist for that specific event.

Fix

The field must be present as an empty array, never omitted. This is the offline Worker’s direct LinkedIn Conversions API integration, not the online GTM-based Insight Tag — see the Offline Conversion Loop infrastructure page.

11

A Google Sheets tab name with special characters broke A1-notation range references

Symptom

A backend integration reading/writing the leads Sheet failed silently on range references.

Root Cause

The integration assumed a plain tab name (Leads), but the real tab name (Digital Asur — Leads, containing an em dash and spaces) requires the tab name to be wrapped in single quotes within any API range reference.

Fix

Wrap tab names containing spaces or special characters in single quotes for every A1-notation range reference.

12

An inconsistent “skip if no data” check across two near-identical integrations

Symptom

Rows with genuinely no identifying data (an expected scenario given an optional email field) showed up as LinkedIn failures rather than clean, expected skips.

Root Cause

Meta’s CAPI integration correctly pre-checked for the presence of at least one identifier before attempting a push — the equivalent LinkedIn integration lacked this same check.

Fix

Added the matching pre-check to the LinkedIn push path: skip cleanly, increment a dedicated counter, and never attempt (or count as a failure) a push for a row with zero identifiers.

13

A tag missing consent gating entirely, only discovered by cross-referencing real GTM exports against this document

Symptom

LinkedIn - Conversion (Generate Lead) had zero consent gating configured, meaning it would fire regardless of visitor consent. Not caught during the original build’s testing.

Root Cause

Surfaced only when a separate AI session, given the raw container export as ground truth, checked every tag’s actual consent configuration systematically rather than trusting the accompanying documentation’s claims.

Fix

Confirmed live via direct testing (declined consent → submitted a lead → tag fired anyway), then fixed with an Additional Consent Check requiring ad_storage + ad_user_data. A follow-up round then found the fix had also attached a Consent Update retry-trigger to this same event-driven tag — recurring the exact mistake from #3 on a different platform. That trigger was removed in a later round, confirmed via the export showing exactly one firing trigger (Generate Lead Event) remaining.

14

A live secret exposed via a routine GTM container export

Symptom

A real, live Meta CAPI access token was found in plaintext inside a shared container export file.

Root Cause

Exporting a GTM container as JSON includes every Constant variable’s literal value, including secrets like access tokens — regardless of which container (Web vs. Server) the secret lives in.

Fix

Treat any GTM container export file itself as sensitive if it contains real Constant-type secrets, and rotate any credential that was ever included in a widely-shared export — independent of whether the container placement itself was otherwise correct.

15

A verification gap that took an unusually long time to resolve, and did so in a genuinely interesting way

Symptom

Multiple well-isolated test attempts across several sessions all came back inconclusive for the Meta CAPI tag.

Root Cause

Real live confirmation finally arrived unprompted — a timestamped Lead event appeared in Meta’s Test Events tool showing "Received from: Server," correlated with a real, simultaneous increase in Stape’s own request counter. The event was marked "Deduplicated" despite showing no visible Event ID — the project never built the explicit event_id-sharing mechanism between the client-side Pixel and server-side CAPI tag, so Meta most likely deduplicated using a fallback signal (the shared _fbp/_fbc browser cookie) instead.

Fix

The CAPI tag is confirmed genuinely working, via an implicit fallback matching method rather than the more precise, Meta-recommended explicit event_id method. See the Event ID Deduplication guide for closing that remaining gap.

16

Server-side “Automap User Data” silently failed for custom-named parameters

Symptom

Even after confirming user_email/user_phone were genuinely present and correctly populated in the outgoing GA4 event (verified via Tag Assistant, Values mode), Meta’s Test Events tool consistently showed no Email/Phone in that event’s "User data keys."

Root Cause

GTM server-side Event Data variables, when reading GA4-client-parsed events, must reference nested paths (params.user_email), not flat top-level keys (user_email) — GA4’s actual Measurement Protocol structure nests custom event parameters under a params object. Not found in any official documentation or practitioner writeup — identified as a well-reasoned hypothesis, then confirmed correct only by testing it live.

Fix

Built two Event Data variables with keys params.user_email and params.user_phone, then manually added two Property rows in the CAPI tag’s User Data section (Email/Phone), leaving "Automap User Data" checked alongside these explicit overrides, not replacing it. Verified fixed: Meta’s Test Events tool subsequently showed User data keys: Email address, Browser ID, IP address, Phone number, User agent.

17

A second, distinct GTM editor-time false positive

Symptom

"Cannot detect if the Google tag is in your container" appears in the GTM editor.

Root Cause

Appears specifically when a Conversion ID field references a variable rather than a literal typed string, because GTM’s static editor-time validator cannot resolve variables at edit-time (only at runtime).

Fix

Unrelated to the "Failed" Preview-status false-negative (#7) — both are real, separate, documented quirks worth not chasing as if they were genuine errors, once confirmed benign.

18

YouTube duplicate-firing diagnosis technique

Symptom

Suspected two independent tracking systems both firing for the same event.

Root Cause

Confirmed by checking the fired event’s own field list for values one system’s code doesn’t reference at all — videoDuration/videoCurrentTime/videoElapsedTime/videoVisible appeared despite the custom-built tracking code never setting any of those fields, directly proving GTM’s native auto-detection was firing independently and simultaneously.

Fix

A useful diagnostic method worth keeping regardless of this specific bug’s outcome (ultimately deferred unresolved — see YouTube Engagement goal page).