DEV Community

Aleksander Sekowski
Aleksander Sekowski

Posted on

TCF Explained: How TC Strings on the Tag and Bid Gate Personalized Ads

On 23 October 2026, IAB Europe’s deadline passed for web CMPs to ship the TCF 2.4 disclosures (timeline confirmed in IAB Europe’s July 16 comms). The same week, Google moved AdSense TCF string errors out of a standalone report and into Policy center under Regulatory issue. Both stories land on the same wire object: the TC String that rides gdpr_consent on pixels and inside GPP on OpenRTB bids. A trafficking sheet can show gdpr=1 and a long base64 blob while the creative you bought still must run as non-personalized, or not at all.

That gap is why “we passed consent QA” and “this line item can use audience data” are different claims. The TC String is not decoration. It is the encoded answer to which purposes and vendors may process data for this impression.

What the TC String actually carries

IAB Europe’s Transparency and Consent Framework stores consent in a compact bitfield string, usually exposed as gdpr_consent= on a tracking URL or embedded in a GPP section on the bid. The first bits declare the TCF policy version (version 2 for every production string you should see today). Later segments list purposes, special features, vendor consents, and legitimate-interest flags the CMP collected from the user.

A demand-side platform does not read the banner text. It reads those bits. If purpose 1 (store and/or access information on a device) is off, many identity and retargeting paths are off, even when the VAST or HTML creative is technically valid. If the vendor ID for your measurement partner is absent from the consent section, the verification pixel in the tag may fire, but the vendor was never authorized for that hop.

One field-level mistake shows up constantly in production: gdpr_consent=1. That value is valid base64 alphabet soup and not a TC String. Pixels and ad servers sometimes map a boolean “GDPR applies” into the consent parameter slot. Downstream code that tries to decode it as TCF gets garbage or rejects the request. The user saw a CMP; the wire carried a stub.

https://example.com/px?id=1&gdpr=1&gdpr_consent=1
https://example.com/px?id=1&gdpr=1&gdpr_consent=CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA
Enter fullscreen mode Exit fullscreen mode

The first URL looks compliant in a spreadsheet. The second carries a decodable signal. Personalized eligibility starts only after decode.

On the tag: from CMP callback to fired pixel

The grant path is familiar. The CMP fires __tcfapi, your tag manager writes gdpr and gdpr_consent, Floodlight or a vendor collector receives both. QA copies the fired URL from Network, not the ad-server template with ${GDPR_CONSENT} still unexpanded.

Two failure modes gate creatives even when XML or HTML validates:

Duplicate keys. Wrappers that append the publisher’s macros and their own often produce two gdpr_consent parameters. The spec expects each signal once. Two identical TC Strings are still ambiguous: the callee may pick the wrong copy, or the copy added by an outer ad server may disagree with the inner tag. That pattern is documented in duplicate consent signals on one URL.

Revoke that never reaches the wire. Withdrawal has to change the same artifact that carried the grant. If the banner flips to “reject” but the next facebook.com/tr or DoubleClick activity still carries the pre-revoke string, vendors keep processing on a yes the user withdrew. Research on top sites consistently finds post-revoke strings that still encode grant; the write-up on consent revocation on the wire walks the accept-then-revoke capture sequence.

US state traffic adds a parallel migration story. us_privacy=1YNN remains a well-formed four-character signal, but IAB Tech Lab deprecated US Privacy on 31 January 2024 in favor of GPP. Shape-valid us_privacy and deprecated us_privacy can both be true at once. A CTV or web tag that only modernized the macro name without sending gpp and gpp_sid can look fine in California trafficking while the bid path already expects GPP sections.

On the bid: GPP, regs, and whether the creative matches

OpenRTB carries consent in regs.gpp, regs.gpp_sid, and in older integrations user.consent (TC String) plus regs.ext.gdpr. Prebid and SSP adapters map CMP output into those fields. The creative decision is still downstream: given these purpose bits, may this line item use this audience or this measurement vendor?

GPP wraps multiple section types in one string. Section IDs in gpp_sid tell you which grammar to decode (TCF, US national, state appendices). A bid with gpp_sid=2 but a malformed section body fails the same way a bad pixel URL fails: the auction may proceed, but brand safety, identity, and personalization modules should treat the impression as restricted.

For EU transparency rules on digital services, OpenRTB also gained DSA objects on the request and response. How buyers surface paid messaging interacts with consent, but the TC String remains the EEA/UK workhorse for lawful-basis signaling on the tag. DSA transparency on the bid is the rtblint-side companion when your gate is the auction object rather than the pixel.

How you catch it

An LLM implementing a CMP adapter, a Prebid consentManagement module, or a server-side tag can emit gdpr_consent=1, duplicate parameters, or a grant string copied from yesterday’s session. The HTTP request still returns 200. The wire contract does not move.

pixellint (cargo install pixellint, npm install pixellint) is the deterministic check for IAB privacy strings on pixel URLs and related JSON bodies: TC String version bits, malformed us_privacy, duplicate_signal, deprecated US Privacy, and template macros left unexpanded. It is independent of IAB Tech Lab and of IAB Europe. It does not decide lawful basis; it tells you whether the hop you captured matches the grammar you think you shipped.

Paste the fired URL into the pixellint playground or run pixellint validate url on the live hop. For server events, validate the JSON body the same way after revoke, not only after accept. When the same session also serves video, consent macros often ride VAST Impression and Tracking URLs: run the live tag through the VAST tag tester and walk wrapper chains with the VAST inspector so creative XML and privacy query params are checked on the hop that actually serves.

Where to go next

If you already run GPP on the bid and tag, treat TCF as the section inside GPP for EEA/UK, not as a separate checkbox on the trafficking sheet. After 23 October 2026, CMP disclosures on web must match TCF 2.4; your fired URLs should still decode the same way they did before, or you have a macro or wrapper bug, not a policy PDF problem.

Top comments (0)