On 23 October 2025 IAB Tech Lab opened public comment on H2 2025 Global Privacy Platform updates: four new U.S. state sections and a rearchitected state-string layout with explicit section headers. That is not a CMP banner story. It is a wire-format story. The same month, traffickers still paste TC Strings into gpp, leave us_privacy=1YNN on CM360 pixels that expect GPP National, and ship OpenRTB bids where regs.gpp_sid survives a hop but regs.gpp does not. Every one of those URLs can look "privacy complete" in a spreadsheet while the downstream callee runs the wrong decoder.
This sheet is for ad ops and bid engineers who own the live tag URL, the Floodlight path, or the OpenRTB regs object and need one place to map parameter name → grammar → where it must land. One malformed field is never the whole job; the job is knowing which family you actually have before you argue with fill or attribution.
The sheet
| Signal family | Typical pixel / ad-server slot | OpenRTB 2.6 home | How you know the grammar | Wrong cousin engineers swap in |
|---|---|---|---|---|
| IAB TCF v2 TC String | gdpr_consent (with gdpr=1) | user.consent (TC String) | Decoded TC version field is 2; core segment is long (not a single digit) | gdpr_consent=1 or true (valid base64, not a TC String) |
| Global Privacy Platform | gpp | regs.gpp | GPP string header type 3 after decode | TC String copied into gpp (decodes as type 2, wrong parameter) |
| GPP section in force | gpp_sid | regs.gpp_sid (array of section ids) | Integer(s): e.g. 7 US National, 8 California, 2 TCF section inside GPP | gpp_sid present while gpp is empty or a TC-only blob |
| IAB US Privacy (legacy) | us_privacy | regs.us_privacy (deprecated) | Four characters: version digit + three Y/N/- | Treating 1YNN as GPP National v2 on products that read GPP only |
| GDPR scope flag | gdpr | regs.ext.gdpr / impression regs | 0 or 1 only | gdpr=1 with missing or placeholder gdpr_consent |
| Google Additional Consent | addtl_consent | exchange-specific extensions | AC string for Google ATP vendors | Used as a stand-in for TC on tags that still require gdpr_consent |
| Duplicate consent keys | same URL twice | duplicate regs fields | At most one authoritative value per signal | Two gdpr_consent or gpp values on one pixel (callee must guess) |
OpenRTB and the pixel are parallel hops, not aliases. A CMP can be correct in the page and still wrong on the request the vendor logs if the ad-server macro never expanded. Floodlight-style path parameters count the same as query keys: if the string is not on the HTTP request the collector sees, it does not exist for billing or restriction logic.
For the October GPP release specifically, new state sections and subsection headers change what parsers must expect inside a type-3 container. Our write-up on the new sections and OpenRTB regs.gpp tracks what landed in that comment package; your CMP version and your bid adapter version can drift on different calendars.
Three rows that validate and still fail in production
gdpr_consent=1. Alphabet and base64 validators green-light it. A TC decoder rejects it immediately because there is no version-2 bitfield and no purpose vector. Google tags interpret gdpr=1 as "TC applies"; an empty or numeric placeholder is how personalized ads quietly turn off while the tag still "has a consent param."
TC String in gpp with gpp_sid=2. The blob is long, base64-safe, and familiar. Decoded header type is 2 (TC), not 3 (GPP). Campaign Manager 360's own documentation says TCF strings sent through GPP are not accepted on that hop; the section id names TCF while the product still wants National or supported state sections on gpp / gpp_sid. We walked through that mix-up on CM360 GPP National v2 versus us_privacy.
regs.gpp_sid without regs.gpp on the bid. Diff tools flag it as incoherent OpenRTB: you told the exchange which GPP section is in force but did not ship the string. Prebid Server and exchange normalizers do not always drop both fields together; one side of the hop can inherit a section id from a template while the GPP body was stripped for size. Buyers read that as "restrict processing" with no payload to parse.
How you catch it
An LLM implementing tag macros or OpenRTB regs can emit plausible key names and still ship the wrong grammar. The RPC or the ad server can return 200. The wire contract does not move.
Pixellint (cargo install pixellint, npm install pixellint) decodes IAB consent strings on the pixel URL and path-shaped tags instead of treating them as opaque base64. It checks TC version bits, GPP header type, deprecated us_privacy, duplicate signals, and template macros that never expanded. It is independent of IAB Tech Lab and of AAO; it is the deterministic check on the string your tag actually fired.
Paste a live URL into the playground or run CLI validation in CI on exported tag templates before traffickers clone them across regions.
Where to go next
- GPP strings and
gpp_sid(header type 3, section ids, TC-in-GPP mistakes) - TCF v2 on pixels (
gdprflag, TC String length and version) - Consent on the wire (query vs path, empty macros, vendor-specific dialects kept separate)
- Consent overview and deprecated US Privacy (31 January 2024 deprecation vs tags that still emit
1YNN)
When the bug is on the bid object rather than the pixel, pair this sheet with OpenRTB privacy field docs on the exchange side; the header rules are the same even when the parameter names move from gdpr_consent to user.consent and from gpp to regs.gpp.