pixellint

Consent · PMs · engineers · marketers

A banner that does not block still fires the pixel

Legal asked for a banner. Engineering added a div. The Meta pixel in head does not read the div. Network tab is the audit, not a screenshot of the modal.

What blocking looks like

No collector request until grant, or a request with Consent Mode denied flags and without advertising cookies. If facebook.com/tr fires on landing with a full _fbp write before click, you did not block. A modal, a footer bar, or a wrapper that only CSS-hides the page still lets GTM run All Pages tags on Container Loaded.

An ad blocker that matches facebook.com/tr never starts the request. A CMP that never queued fbq looks the same in a sparse Network tab. Disable the extension, keep the banner up, watch whether the request appears. If it appears, you are not blocking. If it never appears with the extension off, the wrapper is holding, or the tag is broken. Those two failures need different owners.

https://www.facebook.com/tr?id=1234567890123456&ev=PageView&noscript=1

GTM load order

Built-in Consent Overview is the map of which tags require which signals. A custom HTML tag that injects fbq ignores that map unless you added a consent check. Custom HTML is where banners go to die. Blocking is a load order: CMP stub, consent default denied, wait, update, then fire.

Consent Initialization before Container Loaded is not optional decoration. Tags that fire on Container Loaded with no consent requirement will run under the banner. Moving the pixel to a custom HTML tag named wait for CMP does nothing unless the tag actually waits. Read the tag's consent requirement, then refuse on a fresh profile, then watch Network.

First paint is the leak

QA on a second pageview is not QA. The first view is the one that leaks. Use a fresh profile, refuse, accept, and refuse again. Confirm the collect and ads requests change. Confirm a fired URL in Pixellint carries a decoded string, not a placeholder, once the user has accepted and the IAB hop is allowed to fire.

SPA routers make this worse. A client-side navigation can fire All Pages again without re-showing the banner. If the first view leaked, every virtual pageview leaked. If the first view held, confirm the router does not inject a second container that has no consent wrapper.

CAPI outruns the banner

A server event can outrun the banner if your backend sends Purchase on order create regardless of consent. Same policy question, different pipe. Decide per event type. Server-side GTM and CAPI will still fire if you did not gate those too.

A blocked browser tag plus an ungated Purchase postback is how you honor the banner in Chrome and ignore it in the warehouse. Store the CMP choice with the session or the order. Skip CAPI, or send a redacted event, when the basis is missing. Consent Mode updates gtag. It does not update your shop backend.

After grant, still a real string

Once the user accepts, the next hop is parameters on the pixel: gdpr=1, a real TC String, GPP, Consent Mode updates. A banner that blocks and then fires gdpr_consent=true still failed. Blocking was the easy half. The wire still has to carry a decoded v2 string, not a boolean.

pixellint validate url on the fired request after accept. Look for core.privacy.tc_string_version if the first six bits are not 2. Look for core.privacy.gdpr_consent_malformed if the alphabet is wrong. Look for nothing if the CMP mapped correctly. The modal screenshot does not substitute for that paste.

https://example.com/px?id=1&gdpr=1&gdpr_consent=true

Check the artifact

Paste the pixel URL or JSON body into the playground. Same engine as pixellint validate. Nothing leaves the tab.