IAB TCF Consent String Decoder

Paste a TC string to see what it actually grants: which of the eleven purposes carry consent, which vendors are covered, what the publisher has restricted — and where the string breaks TCF policy while still decoding perfectly. That last part is the point. A malformed string is easy to spot; a well-formed one that vendors quietly refuse to honour is what costs you revenue.

Read it from the euconsent-v2 cookie, the gdpr_consent parameter on a tag, or user.ext.consent in a bid request.

Runs in your browser · nothing sent, stored, or logged

Specification

IAB TCF v2.2 — TC string core, disclosed vendors and publisher TC segments

Bit layout implemented from the IAB Tech Lab consent string format specification. Purpose and special feature names, and 1,202 vendor IDs, are transcribed from Global Vendor List 171 itself. Both verified 2026-08-10. Decoding runs entirely in your browser.

A string that decodes is not a string that works

Most consent decoders answer one question — what do these bits say — and stop. That question is rarely the one you have. By the time anyone pastes a TC string into a tool, something has already gone wrong: European fill has collapsed, a vendor reports no consent for traffic the CMP swears is consented, or an audit has asked why a vendor was active. In every one of those cases the string usually decodes fine. The fault is a level up, in policy. Under TCF v2.2 the global consent scope was removed, so the IsServiceSpecific bit must be 1 and a CMP still emitting 0 is running an old build. Policy versions below 4 are pre-v2.2 and the major buyers stopped honouring them. Five of the eleven purposes may never run on legitimate interest, so a string asserting it for purpose 3 is claiming a legal basis that does not exist. None of these produce a parse error anywhere in the chain — the signal is accepted, read, and then discounted. This decoder reports them as findings alongside the field dump, because the field dump on its own has never once explained a revenue drop.

The bits that people misread

Three fields cause most of the confusion. Purpose numbering is the first: TCF v2.2 renamed everything into plain language and the numbers are not in an intuitive order — purpose 5 is about content profiles, not advertising, and "use limited data to select content" was appended as 11. A summary table copied from a blog post is often still carrying the v2.0 names, which is why the names here come from the Global Vendor List file rather than from a secondary source. The second is legitimate interest, which reads like a weaker yes and is not: it is a different legal basis with different obligations, and the two bitfields are independent, so a purpose can carry both, either, or neither. The third is publisher restrictions, the least understood part of the string. A restriction narrows what a named vendor may do for a named purpose, and because it is expressed as a vendor range it is easy to set far more widely than intended. Requiring legitimate interest for a consent-only purpose is the classic version — it looks like a tightening, and it silently switches those vendors off for that purpose entirely.

Reading the vendor sections

The vendor lists are encoded one of two ways and both mean the same thing, which trips people comparing strings. A CMP writes either a bitfield — one bit per vendor ID up to the maximum — or a set of ranges, whichever comes out shorter, so the same consent state produces different-looking strings from different CMPs. Neither is more correct. What is worth checking is the relationship between the sections. Vendor consent and vendor legitimate interest are separate sets and a vendor commonly appears in both. The disclosed vendors segment, when present, is the record of what the user was actually shown, and a vendor holding consent without appearing there is the finding that turns up in compliance audits. An empty vendor consent section combined with consented purposes is another: the purposes apply to nobody, so every vendor reading the string finds itself absent and falls back to no consent — which looks, from the outside, exactly like a broken CMP.

Frequently asked questions

Where do I find the consent string?
In three places, depending on where you are standing. In a browser it is the euconsent-v2 cookie, written by the CMP on the publisher's domain. On a tag or pixel it arrives as the gdpr_consent parameter, alongside gdpr=1. In a bid request it sits at user.ext.consent, with the regs.ext.gdpr flag next to it. All three carry the same string, so if delivery is fine in one place and broken in another, the fault is in whatever failed to pass it along rather than in the string.
Why does a string decode fine and still get treated as no consent?
Because decoding only proves the bits are well formed. A string can parse perfectly and still be rejected: the policy version can predate v2.2, the CMP ID can be missing from the registered list, the scope bit can claim the retired global scope, or legitimate interest can be flagged for a purpose that only permits consent. Vendors validate against policy, not just format, and the usual symptom is not an error message anywhere — it is programmatic revenue quietly dropping on European traffic.
What is the difference between consent and legitimate interest here?
Two separate bitfields for the same eleven purposes, carrying two different legal bases. Consent is the user agreeing; legitimate interest is the vendor asserting a lawful basis the user may object to. They are not interchangeable, and five purposes may never use legitimate interest at all — purpose 1 (device storage), 3 and 4 (personalised advertising profiles) and 5 and 6 (the content equivalents). A string flagging legitimate interest for any of those is describing something the framework does not allow, and this decoder marks it invalid rather than displaying it as a second kind of yes.
Why are some vendors in my string not named?
Because the Global Vendor List moves. This page resolves IDs against list version 171; a vendor registered after that snapshot, or removed from the list since, shows as an unknown ID rather than a guessed name. The ID itself is still correct and still meaningful to the vendor it belongs to — an unnamed ID is a gap in this page's reference data, not a fault in your string.
What does the disclosed vendors segment actually do?
It records which vendors the user was actually shown. That makes it the segment auditors care about, because consent recorded for a vendor who never appeared in the CMP interface is not valid consent no matter how cleanly it encodes. When both segments are present this page compares them and flags any vendor that has consent without disclosure. It is an optional segment, so its absence is not itself a fault.
Is my consent string sent anywhere?
No. The decoding is arithmetic on bits and the vendor list is a static file, so all of it happens in your browser. Nothing is uploaded, logged or stored. That matters more than usual here: a production TC string is a record of a specific person's privacy choices, and pasting one into a tool that phones home would be its own small privacy incident.

Related