martechdevs has been acquired by Growth and Analytics Partners LLC

Tracking troubleshooting

Consent debugging

Proves whether consent defaults, updates and withdrawals actually control what every tag sends, using outgoing requests, cookies and Tag Assistant as evidence. Covers Google Consent Mode v2 signals, basic vs advanced, region defaults, wait_for_update, url_passthrough and ads_data_redaction, the gcs, gcd and UET asc parameters, GTM consent settings, Cookiebot and OneTrust, late banners, and Meta, TikTok, LinkedIn, UET and product analytics pixels. Produces a region-by-choice test matrix and a pass or fail report.

FreeVersion 0.1.0Reviewed 17 October 2026

Proves, case by case, that the visitor's consent choice controls what each tag stores and sends. A visible banner, a green CMP dashboard or a "consent mode detected" badge is not evidence. The evidence is the consent state the tags saw, the requests that left the browser and the cookies that were written, captured per region and per choice against a written expected behaviour.

When to use

Use this skill when:

  • Consent mode is installed but GA4 or ad platform data dropped, or data appears for visitors who rejected.
  • Tags, pixels or cookies appear before the banner is answered or after a reject.
  • A CMP was installed, upgraded, replaced or reconfigured, or a new region rule was added.
  • GA4 Consent settings, Google Ads conversion diagnostics or the Microsoft UET dashboard warn about missing consent signals.
  • A banner or tag release needs a documented pass or fail before it ships.

Use something else when:

  • Nothing is implemented yet, or the question is basic vs advanced, which CMP, or which countries need consent: use the consent-mode-v2-setup skill. Legal questions go to the privacy owner.
  • The whole container needs auditing, not just consent: use gtm-container-audit.
  • Browser evidence passes but consent is lost between a server container and a destination: use server-side-tracking-debug.
  • Consent is verified and the question is why platforms and analytics disagree: use platform-number-reconciliation.
  • Sessions break across domains or SPA routes: use cross-domain-and-spa-qa, then return here for the consent cases.
  • If a named skill is not installed, say so, record that area as not covered in the write-up, and do not improvise its work.

Inputs

Read these first if they exist:

  • martech-context/stack.md: CMP, containers, hardcoded tags, server container, tag gateway, vendor proxy hosts, owners.
  • martech-context/decisions.md: the approved consent model (mode per region, category mapping, withdrawal rule).
  • martech-context/tracking-plan/: the consent category on each event contract.

Then gather:

  • The approved consent specification. For each region: the default for each Google signal, the banner type, basic or advanced for Google tags, which vendor sits in which CMP category, what dismissing the banner means, whether implied consent or Global Privacy Control applies, what happens to events before a choice, and what withdrawal must stop. A test without an expected result cannot fail.
    • If none exists, draft one with the user from the CMP and GTM configuration. Label it "derived from current configuration, not approved" and mark every value the privacy owner has not confirmed as unconfirmed. A draft built from the configuration turns today's bugs into expected results, so no verdict goes above Incomplete until the owner approves it.
  • Journeys to test: a landing page, a lead form, checkout or signup, one SPA route change, one cross-domain hop.
  • Conversion gate. Conversion cases (C9, C12) and a test click ID on the landing URL write to live systems (CRM records, orders, conversions that Ads and Meta bid on, GA4 sessions labelled paid). Run them only after the site owner approves in writing; record where they run, the test record markers, the exclusion from Ads and Meta and the cleanup owner, and use test payment methods only. Without approval, mark them "not run" with that reason. Details: references/test-matrix.md.
  • Regions in scope and how you will appear to be in each (VPN or proxy egress).
  • Read access: a GTM container export or read-only API access, CMP admin read access or the CMP's public configuration file.

Never ask for, print or store credentials or customer personal data. HAR files and cookie dumps hold identifiers: store them with the project, redact before sharing, and record cookie names rather than values.

Procedure

How the agent runs this

  • Mode A, the agent has its own browser (agent-owned or Playwright, never the user's everyday browser): a fresh context per run, region from a proxy or VPN egress only (geolocation emulation does not change the IP), HAR and all cookies including HttpOnly captured through the tool, real banner buttons clicked for sign-off.
  • Mode B, no browser tool: give the user the steps per case, then analyse the HAR, snapshot, cookie list (HttpOnly column) and Tag Assistant Consent tab they return.
  • Either way, read every HAR through scripts/har-consent-extract.mjs, which prints the consent timeline in order. Details: references/test-matrix.md.

For quick triage, run the five-minute first check in references/test-matrix.md. It finds obvious faults; it is never a sign-off.

1. Write the expected behaviour before testing

Copy assets/consent-test-matrix.csv and fill one row per region and choice: each Google signal, Google behaviour, UET asc, url_passthrough and redaction, each non-Google vendor, cookies allowed, and whether the essential journey completes. Cases C0 to C14, region list, minimum set and run rules: references/test-matrix.md.

  • If the specification does not say basic or advanced for Google tags, stop. Basic sends nothing to Google for a denied visitor; advanced sends cookieless denied-state requests. The same request passes in one and fails in the other.

2. Inventory every consent writer and every sender

  • Writers of the Google default: the CMP template in GTM, a hardcoded gtag('consent', 'default', ...), a CMS plugin, a second container, the Google tag settings "Set consent mode override" and "Manage default consent settings", and TCF when the CMP runs it.
  • Senders: GTM tags, hardcoded pixels in the theme or app, embeds and iframes, Google tag gateway or CDN injection, server-side containers, vendor proxy hosts.
  • Find them from the page source, network initiator chains, the GTM export and the CMP's published configuration.
  • Decision rule: more than one writer of the Google default is a finding even when the values agree today.

3. Prepare a clean rig

  • One fresh profile per case, no stored consent, no ad blocker. Network log with "Preserve log" and cache disabled; a HAR per case.
  • Cookie evidence comes from DevTools Application > Cookies (HttpOnly column) or the HAR's Set-Cookie headers. document.cookie and the snapshot cannot see HttpOnly cookies such as a server-set FPID.
  • Confirm the CMP sees the intended region (for Cookiebot, Cookiebot.regulations.gdprApplies; a CookieConsent value of -1 means no consent is required and everything is accepted).
  • Connect Tag Assistant. Run scripts/consent-snapshot.js at each checkpoint.

4. Test the default (no interaction)

  • Tag Assistant: the earliest Consent event lists all four signals with the expected values and comes before the first tag. An empty Consent tab means consent mode is not implemented. "Could not connect" means the container or Google tag is blocked, which is expected in basic mode before a choice.
  • Basic: no Google measurement requests and no _ga, _ga_*, FPID or _gcl_* cookies.
  • Advanced: Google requests carry denied state in gcs and gcd, and none of those cookies are written.
  • Non-Google vendors: no event requests or cookies unless the vendor holds data under an approved consent API. A library load alone is not an event.
  • Microsoft UET: asc=D or no UET events. Denied beacons go to bat.bing.net, so filter on both UET hosts.
  • Run race-sensitive cases three times, one with network throttling. A case passes only on three of three.

5. Test each choice (update)

Reject all, accept all, each partial choice, closing the banner (C10) and browsing without a choice (C11).

  • The latest Consent event shows the update, and the next requests carry the new state (UET asc=G after a grant).
  • A tag blocked at page load fires exactly once after acceptance on the same page. The first page view is neither lost nor duplicated.
  • No business event (purchase, lead) fires because consent changed.
  • After every reject, the essential journey (form, checkout, login) still completes.
  • Events held before the choice: TikTok's holdConsent releases its queue on grantConsent, and Amplitude sends events tracked before init. Compare with the specification; C12 tests a conversion before any choice.

6. Test returning visitors and navigation

  • Reload, then navigate. The stored choice must be in place before the first tag.
  • Decide on the outcome: after a stored grant, the first Google request's gcd letters show r or v, not p, and Tag Assistant shows the update before the first tag.
  • On a failure, find why the stored choice is not applied at Consent Initialization before anyone proposes a longer wait_for_update. Google does not document when that wait starts; report any timing as approximate, from the consent default.

7. Test withdrawal

  • Reopen preferences (Cookiebot.renew(), the OneTrust preference centre) and withdraw.
  • An update to denied is sent on the same page, later requests carry denied state, and non-Google vendors stop (their revoke calls run, or they no longer load).
  • Meta: no automatic events after withdrawal on the same page. A loaded pixel keeps sending unless fbq('consent', 'revoke') runs; GTM blocking alone does not stop it.
  • Record whether existing cookies are deleted or left, and confirm none is refreshed. Whether they must be deleted is a specification decision.

8. Test region branches

  • Every region default and the unknown-location fallback. Codes are ISO 3166-1 alpha-2 or ISO 3166-2 (GB, not UK; US-CA). The more specific region wins.
  • The CMP's geolocation rule (which banner shows) and the Google region defaults are separate settings that must agree.
  • A CMP location override proves the banner rule only. Google region defaults are proven only from a matching IP egress. Record the CMP region flag and the first request's gcd default letter for every region case.
  • Global Privacy Control (C13) in opt-out regions; CMP blocked (C14) in the main opt-in region.

9. Test url_passthrough and ads_data_redaction

Run in C0, C1 and C2 with the approved test click ID. Full evidence rules: references/evidence-and-signals.md.

  • url_passthrough: same-domain links gain _gl or the click parameter, and the next page's Ads and GA4 requests carry the click while no _gcl_* cookie exists. Fail when it is lost on a redirect, a POST form, or a canonical or cache rule.
  • ads_data_redaction: only while ad_storage is denied, only on Ads and Floodlight requests. Pass when the click ID appears in no click-identifier parameter there.

10. Read the lagging destination signals

GA4 Admin consent settings, Google Ads conversion diagnostics, the UET dashboard and the GA4 BigQuery privacy_info fields confirm the pattern days later. They never replace browser evidence. Paths, lags and a per-country query: references/evidence-and-signals.md.

11. Write up pass or fail

Use references/pass-fail-writeup.md. Grade every failure:

  • S1: data sent or storage written beyond what the visitor's current choice allows. An essential journey that breaks after a reject or withdrawal is graded like S1, owned by the site owner.
  • S2: permitted data lost or duplicated.
  • S3: configuration risk with no wrong behaviour observed yet.
  • Verdict: Fail with any open S1. Otherwise Incomplete while any minimum-set case is not run or the specification is unapproved. Conditional pass with S2 only when each has an owner, a date and the user accepts it. Pass with S3 only or none.
  • Specification gaps (an undefined region, no rule for GPC or implied consent) go in their own list for the privacy owner. They are not test failures.

Depth for each layer: references/gtm-consent-settings.md, references/cmp-integration-traps.md, references/non-google-tags.md.

Common failure modes

  • Default after the first tag. Detect: Tag Assistant flags it; a Google request precedes the first Consent event; it varies with throttling.
  • Update without default. Detect: no default in the earliest Consent event; gcd letters m or n.
  • Two writers. Detect: two consent default entries, values that change between page loads, or a TC string that disagrees with gcs.
  • Wrong mode delivered. Detect: Google tags with "Require additional consent" or exception triggers when advanced was specified; denied-state Google requests before a choice when basic was specified.
  • Missing v2 signals. Detect: ad_user_data or ad_personalization absent from the default; GA4 consent settings alert.
  • First page lost after accept. Detect: blocked tag on All Pages with no consent-update trigger.
  • Duplicate page view. Detect: one tag on both All Pages and the CMP's update event.
  • Banner late. Detect: CMP script async, deferred or reordered, or Google tags injected by a CDN.
  • Identity outside cookies. Detect: GA4 cid stable across pages with analytics storage denied and no _ga; an HttpOnly FPID.
  • Pre-consent events released on grant. Detect: requests after accept carry events from before it.
  • Implied consent. Detect: a grant recorded after scrolling or closing the banner.
  • Withdrawal ignored by non-Google tags. Detect: Meta automatic events or other vendor requests after withdrawal on the same page.
  • Region defaults wrong. Detect: UK for GB, no unknown fallback, CMP and Google regions disagree.

Worked example

Acme Outdoor (fictional, example.com, GTM-XXXXXXX) runs Cookiebot through GTM with advanced mode in the EEA and GB. Twenty-one of twenty-eight planned cases ran; the unknown-location cases had no usable egress. Findings: a theme-level gtag('consent','default') without the v2 signals competed with the template (S3); the Meta pixel required ad_storage but stayed on All Pages, so it never fired on the accept page (S2); a returning visitor's first GA4 request went out denied in the throttled run because the stored choice was not applied at Consent Initialization (S2); TikTok released pre-consent events on grant, including a lead submitted before any choice (S1). Verdict: Fail, coverage incomplete. Full write-up: references/pass-fail-writeup.md.

Acceptance checks

  • Specification: approved by the privacy owner, with an expected value for each Google signal and each vendor in every row. Pass: no blank or unconfirmed expectations; otherwise the verdict stops at Incomplete.
  • Inventory: every consent writer and sender is listed with its owner. Pass: each network request in the default case maps to a listed sender.
  • Default: earliest Consent event before the first tag in three of three runs per region. Pass: no late-default error in Tag Assistant and no earlier Google request in the extractor timeline.
  • Choices: for reject, accept, each partial choice and dismissal, requests and cookies after the choice match the row. Pass: zero S1, each blocked tag fires once, and the essential journey completes after every reject.
  • Returning and withdrawal: after a stored grant the first request's gcd letters show r or v; after withdrawal no gated vendor sends, Meta automatic events included. Pass: request parameters and HAR prove it.
  • Regions: each region branch and the unknown fallback ran from the matching IP egress, with the CMP region flag and the gcd default letter recorded. Pass: no region marked pass on a CMP location override alone.
  • Optional settings: url_passthrough and ads_data_redaction match the specification in C0, C1 and C2. Pass: observed_gl and observed_click_id_in_ads filled and matching.
  • Coverage: every minimum-set case ran or is marked not run with a reason. Pass: the verdict is no higher than Incomplete while any is not run.
  • Report: each case cites the HAR and extractor output, Tag Assistant evidence and the snapshot, with run mode, container and CMP configuration versions, browser, date and gate approval. Pass: a reviewer can repeat any case from the record.

Boundaries

  • Read-only. This skill does not edit GTM, the CMP, site code or vendor settings; conversion cases run only under the written approval in Inputs. Fixes are a change list for the owner and stop for human approval. Use gtm-change-workflow for the change; if it is not installed, deliver the change list as a Markdown file and stop.
  • It does not decide what is legally required. Defaults, categories and withdrawal rules come from the privacy owner.
  • Hand-offs and their safe modes:
    • Google Tag Manager has no official Google MCP server. Prefer a container export or the Tag Manager API with the tagmanager.readonly scope. Stape's GTM MCP server mixes reads and writes (including publish and delete) in every tool behind an action parameter, so no tool allowlist makes it read-only; if used, call only the actions get, list, live, latest and getStatus.
    • Google's GA4 MCP server (experimental, read-only scope): its realtime report confirms events arrive after a grant. Read consent state from browser evidence and BigQuery, not reports.
    • Meta's Ads MCP server: call only its read tools. Never call ads_pixel_event_create, ads_pixel_event_update, ads_pixel_event_delete, ads_pixel_parameter_create, ads_pixel_parameter_update or ads_pixel_parameter_delete.
    • Meta's browser extension (now Meta Ads Data Advisor) can apply fixes, so use it to read only. Test Events and TikTok's Pixel Helper are read-only evidence.
    • OneTrust's developer MCP serves API specs for search and reading; its execute-request tool can call live APIs, so it needs approval first.
    • Cookiebot help pages block non-browser clients. Open them in a browser.
    • Microsoft UET consent is checked with the UET Tag Helper extension (it shows asc as words; the request carries G or D) and the UET dashboard.

Live docs

Platform settings, limits and menu paths change. Before stating any parameter name, limit, quota or UI path:

  • Fetch the current page from the vendor docs MCP server or llms.txt listed in sources.yaml, or open the canonical URL.
  • If the live page disagrees with this skill, follow the live page and tell the user what changed.
  • Cite the URL you used.

The entries that matter most: Google's consent mode overview, consent setup and Tag Assistant debugging guides, Cookiebot's GTM and auto-blocking articles, OneTrust's Google Consent Mode article, Microsoft's UET consent page and bat.js, and the Meta and TikTok consent pages. Facts were checked on 2026-10-17. Google does not document the gcs and gcd encoding; the decoding here is community knowledge, so confirm it in Tag Assistant.

Book a Free Call

Thirty minutes on your stack and what it needs. Free, and no pitch.

Thirty minutes, and you leave with a plan

We look at what you have, what it is costing you and what to do about it first.

  • 30 minutes
  • Video call, link on booking
  • No obligation

What we'll cover

  • Your current stack and where it hurts
  • Quick wins we can ship first
  • An integration roadmap
  • Timeline, scope and next steps

Calendar not loading? Open it in a new tab or email hello@martechdevs.com.