Consent · engineers · marketers
The CMP choice has to survive into the URL
Floodlight, many DSPs, and core Pixellint rules read gdpr, gdpr_consent, gpp, gpp_sid, us_privacy off the artifact. They cannot read your React state.
Which fields
For TCF: gdpr is 0 or 1, and gdpr=1 needs a TC String in gdpr_consent. For GPP: gpp is the string, gpp_sid is the section in force. US Privacy may still appear as us_privacy while you migrate. Meta LDU and Google Consent Mode are separate vendor dialects. They do not fill these IAB fields for you.
Pixellint core reads them on the query string and on Floodlight-style path parameters. A semicolon tag on doubleclick.net is not exempt because it looks like a path. If the pair is on the artifact, it is on the artifact. Some vendors have consent fields on a CAPI JSON body. That is a different pack. Do not assume gdpr_consent on a pixel URL is copied into CAPI by magic.
https://ad.doubleclick.net/ddm/activity/src=1234567;type=convr0;cat=purch0;ord=8675309;gdpr=1;gdpr_consent=CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA;gpp=DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN;gpp_sid=2?
Query and path are the same contract
A publisher pixel that puts gdpr=1 on the query and a wrapper that puts gdpr=1 on the path has duplicated the flag. core.privacy.duplicate_signal. A Floodlight tag that only has the pair on the path is complete if the values are right. Do not add a query copy as backup.
VAST and other document-shaped artifacts can carry the same names on tracking URLs. Core privacy rules run on URL-like artifacts. A JSON CAPI body is not this hop. If you need LDU on CAPI, that is data_processing_options on the event, not gdpr_consent in user_data.
Macros
Map CMP output to the ad server's IAB macros. On a template, ${GDPR}, [GDPR_CONSENT_123], and {{gpp}} are correct. On a fired URL they are a miss. Core privacy rules skip unexpanded macros and empty values so a template does not get a malformed-string finding. Macro rules then fail the fired state.
A macro that expands to 1 or true is worse than one that does not expand. It looks populated in a log. It is still not a TC String. Decode it. Confirm on a fired tag, not on the template. Template-versus-fired is the difference between a good GAM creative and a live miss.
https://example.com/px?id=1&gdpr=${GDPR}&gdpr_consent=${GDPR_CONSENT_123}&us_privacy=${US_PRIVACY}&gpp=${GPP}&gpp_sid=${GPP_SID}
Vendor dialects do not fill IAB
dpo=LDU is Meta. ad_storage granted is Google Consent Mode. Neither writes gdpr_consent. A site that only installed Consent Mode still ships Floodlight without a TC String unless the ad server macros are mapped. A site that only mapped TCF still ships Meta without LDU unless dpo is set.
Check the collect URL for whatever Google actually sent, and the vendor URL for gdpr_consent, separately. pixellint validate url on each hop. One paste that contains a gtag collect ping will not certify the Floodlight tag that fired next to it.
Dropouts
A CMP yes that never reaches the ad server, a chain hop that strips the query, or a SPA that fires the tag before the CMP callback, all look like missing consent on the wire. Debug the fired URL, not the CMP dashboard. If Pixellint sees gdpr=1 and no string, the vendor sees the same. That is core.privacy.gdpr_consent_missing.
Redirect chains eat parameters. If hop two drops gdpr_consent, hop three is the miss. See redirect pixel chains. Do not add a third copy of the string as a tie-break. One writer per parameter. One decoded string on the request the vendor actually received.
Check the artifact
Paste the pixel URL or JSON body into the
playground. Same engine as
pixellint validate. Nothing leaves the tab.