Skip to main content
Back to Guides
Compliance14 min read

TCF 2.2 Implementation for Publishers: The Complete Technical Walkthrough

A hands-on implementation guide for TCF 2.2: TC String structure, the __tcfapi CMP API, Global Vendor List management, publisher restrictions, and integration with Google Consent Mode — with working code examples.

If you run programmatic advertising, you've probably heard that you "need TCF 2.2." But hearing it and actually implementing it are different things. This guide skips the policy overview — you can read our TCF for Publishers primer for that — and goes straight to the mechanics: what the spec requires, how the pieces connect, and where implementations break.

We're writing for ad tech engineers, publisher dev teams, and anyone who's stared at a TC String and wanted to understand what's actually inside it.

The Four Moving Parts of a TCF 2.2 Implementation

Every TCF implementation has four components that must work together:

  1. The CMP (Consent Management Platform) — displays the consent UI, collects user choices, and encodes them into a TC String. Must be registered with IAB Europe and assigned a CMP ID.
  2. The TC String — a base64url-encoded binary string that carries the user's consent and legitimate-interest choices, the list of vendors disclosed, and any publisher restrictions. Every ad call on the page includes this string.
  3. The CMP API (__tcfapi) — a JavaScript stub loaded before any vendor tags. Vendors call it to check consent status before processing data.
  4. The Global Vendor List (GVL) — an IAB-maintained JSON registry of every vendor in the framework, including which purposes and legal bases each vendor declares. Your CMP uses it to populate the consent UI and validate vendor claims.

If any of these four pieces is misconfigured, the chain breaks — and the failure mode is usually silent: vendors either can't read consent or read it incorrectly, resulting in lost ad revenue or compliance violations.

TC String Structure and Encoding

The TC String isn't opaque magic — it's a well-defined binary format packed into base64url encoding. Understanding its structure helps enormously when debugging. A TC String contains multiple segments, separated by periods (.):

  • Core segment (always present) — TCF version, creation/update timestamps, CMP ID, CMP version, consent screen number, consent language, vendor list version, policy version, publisher country code, purpose consents (a 24-bit bitfield), purpose legitimate interests, vendor consents (variable-length bitfield or range encoding), and vendor legitimate interests.
  • DisclosedVendors segment (mandatory since TCF 2.3, March 2026) — lists all vendors the CMP actually showed to the user, regardless of whether they received consent.
  • PublisherTC segment (optional) — carries publisher-specific purpose consents and custom purposes, separate from vendor-level consent.

Bitfield vs. Range Encoding

Vendor consent uses either a bitfield (one bit per vendor ID, up to the max vendor ID) or range encoding (start/end pairs for consecutive vendor IDs). The CMP chooses whichever produces a shorter string. Decoders must handle both. The MaxVendorId field tells you the highest vendor ID in the bitfield, and the IsRangeEncoding bit indicates which encoding is used.

Here's how purpose consent is encoded in the core segment. Each of the 24 TCF purposes gets a single bit:

purpose-consent-bitfield.txt
Copy to clipboard
Bit position:  1  2  3  4  5  6  7  8  9  10 ... 24
Purpose:       Store  Basic  Ads  Profile  Measure  ...
Consent:       1  1  0  1  0  1  0  0  0   0       0

In this example:
- Purpose 1 (Store/access on device): CONSENT
- Purpose 2 (Basic ad selection): CONSENT
- Purpose 3 (Personalised ad profiles): NO CONSENT
- Purpose 4 (Personalised ads): CONSENT
- Purpose 5 (Content profiles): NO CONSENT
- Purpose 6 (Personalised content): CONSENT

You don't need to decode this manually in production — the CMP API does it for you — but understanding the structure matters when you're troubleshooting why a specific vendor thinks it doesn't have consent.

The CMP API: __tcfapi

The __tcfapi function is the interface between your CMP and every vendor tag on the page. Per the TCF spec, a CMP must define window.__tcfapi as a synchronous function before any vendor scripts load. The CMP stub must also create window.__tcfapiLocator (an iframe used for cross-domain access via postMessage).

The API signature is:

__tcfapi-signature.js
Copy to clipboard
__tcfapi(command, version, callback, parameter)

// command:   string — the API command
// version:   number — TCF version (2 for TCF 2.0/2.2)
// callback:  function(result, success) — called with the result
// parameter: optional — command-specific argument

Key Commands

getTCData — returns the current TC data (consent string, purpose consents, vendor consents, etc.). Vendors call this to check whether they have consent.

getTCData-example.js
Copy to clipboard

addEventListener — like getTCData, but fires again whenever consent state changes (e.g., when the user updates their preferences). This is what well-behaved vendor tags should use instead of a one-shot getTCData.

addEventListener-example.js
Copy to clipboard

ping — a quick check to see if the CMP is loaded and what state it's in. Returns cmpLoaded, cmpStatus, displayStatus, and gdprApplies. Useful for diagnostics.

ping-example.js
Copy to clipboard

Global Vendor List (GVL) Management

The GVL is a JSON file published by IAB Europe listing every registered TCF vendor, their declared purposes, legal bases, and data retention policies. Your CMP fetches it to populate the consent UI with accurate vendor information.

Where to Fetch the GVL

The canonical URL is https://vendor-list.consensu.org/v3/vendor-list.json for the latest version. Specific versions are at https://vendor-list.consensu.org/v3/archives/vendor-list-v{version}.json. The GVL updates roughly weekly.

What the GVL Contains

Each vendor entry includes: id, name, purposes (consent-based), legIntPurposes (legitimate interest), flexiblePurposes (either legal basis), specialPurposes (no consent required), features/specialFeatures, policyUrl, dataRetention, and localized urls for privacy policies.

GVL Caching: Don't Hit the CDN on Every Pageview

Fetching the full GVL on every page load adds ~300KB of JSON and a blocking network request. Cache the GVL locally and check for updates no more than once per day. Store the vendorListVersion you fetched and compare it against the latest endpoint. Most CMPs (including CookieBeam) handle this caching internally — but if you're building custom integrations or debugging, be aware that stale GVL data can cause your consent UI to show outdated vendor information.

Publisher Restrictions: Controlling Vendor Behavior

Publisher restrictions are one of the most powerful — and most underused — features of TCF 2.2. They let you, as a publisher, override a vendor's declared legal basis for specific purposes.

Why This Matters

Under TCF 2.2, vendors can declare legitimate interest as their legal basis for certain purposes. But as a publisher, you might decide that legitimate interest isn't appropriate for your audience or jurisdiction. Publisher restrictions let you enforce stricter rules:

  • Restriction Type 0: Purpose flatly not allowed — the vendor cannot process data for this purpose at all, regardless of what they declared in the GVL.
  • Restriction Type 1: Require consent — even if the vendor declared legitimate interest, they must have explicit user consent for this purpose.
  • Restriction Type 2: Require legitimate interest — the opposite: force the vendor to rely on legitimate interest instead of consent (rarely used).

Practical Example

Say you want to require consent for Purpose 4 (Create a personalised ads profile) for all vendors, even those claiming legitimate interest. Your CMP would encode this as a publisher restriction in the TC String:

publisher-restriction-example.json
Copy to clipboard

An empty vendorIds array means the restriction applies to all vendors. You can also target specific vendor IDs if you only want to restrict certain partners.

In practice, most publishers should at minimum require consent for Purposes 3 through 6 (ad profiling, personalised ads, content profiling, personalised content). Some DPAs — particularly in France and Germany — have taken the position that legitimate interest is not a valid basis for advertising purposes under GDPR, and regulatory enforcement has consistently backed this up.

Step-by-Step: Implementing TCF 2.2 on Your Site

Whether you're using an off-the-shelf CMP or validating an existing setup, here's what needs to happen in order:

TCF 2.2 Implementation Steps

1

1. Choose a registered CMP

Your CMP must be registered with IAB Europe and have an assigned CMP ID. Only registered CMPs can generate valid TC Strings. The IAB Europe CMP List shows all registered CMPs. If you're evaluating CMPs, verify their registration status before going further. An unregistered CMP produces TC Strings that vendors will reject.

2

2. Load the CMP stub before everything else

The __tcfapi stub must be the first script in your <head>. It needs to be present before any vendor tags attempt to call it. If a vendor tag fires before the stub exists, it may assume GDPR doesn't apply (failing open) or that consent was denied (failing closed — killing your ad revenue).

3

3. Configure your vendor list

Decide which GVL vendors you actually use. Don't disclose all 1,200+ vendors to your users — that's terrible UX and, under TCF 2.2's transparency requirements, arguably non-compliant. List only the vendors you genuinely work with. Your CMP should let you select specific vendors from the GVL.

4

4. Set purpose legal bases and publisher restrictions

For each purpose, decide whether you'll accept consent, legitimate interest, or consent only. Apply publisher restrictions for any purpose where you want to override vendor-declared bases. At minimum, require consent for Purposes 3-6 (advertising-related purposes).

5

5. Configure the consent UI

TCF 2.2 requires that the consent UI clearly present all purposes and vendors, provide granular control (per-purpose and per-vendor), and offer an easy way to withdraw consent. The first layer should describe purposes in plain language. The second layer should show the full vendor list with their declared purposes and privacy policies.

6

6. Test TC String generation

After a user makes a choice, verify the TC String is generated correctly. Use the IAB's TC String decoder tools or CookieBeam's built-in diagnostics to inspect the string. Check that vendor consents, purpose consents, publisher restrictions, and the disclosedVendors segment are all present and accurate.

7

7. Verify vendor integration

Confirm that vendor tags are actually calling __tcfapi and respecting the result. Open browser DevTools, filter network requests, and check that ad calls include the gdpr and gdpr_consent parameters. If a vendor fires before checking consent, that's a compliance violation on your site.

8

8. Wire up Google Consent Mode alongside TCF

TCF and Google Consent Mode are complementary — see the section below. Configure your CMP to emit both the TC String (for programmatic vendors) and Consent Mode signals (for Google tags). Don't treat them as either/or.

CMP Registration with IAB Europe

Publishers don't register as CMPs — they use a registered CMP. But if you're building your own consent solution, here's what CMP registration involves:

  • Application — submit to IAB Europe with documentation of your CMP's TC String generation, __tcfapi behavior, and vendor list management.
  • Compliance check — IAB Europe reviews your implementation against the TCF spec (TC String correctness, API behavior, UI requirements).
  • CMP ID assignment — on approval, you receive a unique numeric ID embedded in every TC String your CMP generates.
  • Ongoing obligations — update when the spec changes, respond to compliance complaints, maintain accurate records.

For most publishers: verify your CMP is on the IAB Europe CMP List. If it isn't, switch — your TC Strings are invalid otherwise.

Integration with Google Consent Mode

This is the question we get most: "Do I need TCF and Consent Mode, or just one?" The short answer: you probably need both. For the full comparison, see our TCF 2.2 vs Google Consent Mode v2 guide. Here we'll focus on the practical wiring.

What Each One Does

TCF produces a TC String that programmatic ad vendors (SSPs, DSPs, ad exchanges) read to determine consent. Google Consent Mode sets gtag consent states (ad_storage, analytics_storage, ad_user_data, ad_personalization) that Google tags read. They're different signal formats for different consumers.

How to Wire Both from One CMP

Your CMP should translate the user's consent choices into both formats simultaneously. When a user grants consent for TCF Purpose 1 (Store/access on device) and Purpose 3-4 (ad profiling/personalised ads), the CMP should also set the Google Consent Mode signals accordingly:

tcf-consent-mode-integration.js
Copy to clipboard

In practice, a CMP like CookieBeam handles this mapping internally — you don't write this code yourself. But knowing how it works helps you verify the implementation is correct and debug issues where Consent Mode signals don't match TC String values.

Common Implementation Mistakes and Debugging

After reviewing hundreds of TCF implementations, these are the errors we see most often:

1. CMP stub loads too late

If vendor scripts execute before __tcfapi exists, they can't check consent. Some vendors fail open (process data without consent — a GDPR violation). Others fail closed (no ads load — revenue loss). The fix: make your CMP the very first script in <head>, before Google Tag Manager, before ad tags, before anything.

script-load-order.html
Copy to clipboard

2. Stale GVL version

Your CMP shows vendors based on the GVL it has cached. If a vendor updates their declared purposes in a new GVL version and your CMP is using a cached copy from weeks ago, you're showing users outdated information. Verify your CMP updates its GVL cache at least daily.

3. Missing DisclosedVendors segment

Since TCF 2.3 took effect in March 2026, TC Strings must include the DisclosedVendors segment — the list of vendors that were actually presented to the user. Strings without this segment are now treated as invalid by compliant vendors. If your CMP hasn't been updated, you're silently losing ad demand because vendors see an invalid consent signal.

4. No publisher restrictions on advertising purposes

By default, many CMPs let vendors use legitimate interest for advertising purposes. In the EEA, DPAs have repeatedly ruled this isn't appropriate. If you haven't explicitly set publisher restrictions requiring consent for Purposes 3-6, your implementation may be technically functional but legally non-compliant.

5. TC String not passed in ad requests

Just having a TC String on the page isn't enough — it must be included in bid requests. Prebid.js handles this automatically through its gdpr module, but custom integrations or direct ad server calls may not. Check your ad calls in the Network tab:

verify-tc-in-ad-calls.txt
Copy to clipboard
// In a Prebid.js bid request, look for:
bidRequest.gdprConsent.consentString  → should contain the TC String
bidRequest.gdprConsent.gdprApplies    → should be true for EEA visitors

// In a direct ad server call, look for query parameters:
?gdpr=1&gdpr_consent=CQHzD...base64string...

6. Consent Mode and TCF out of sync

If your CMP sets TCF consent but doesn't update Google Consent Mode (or vice versa), Google tags and programmatic vendors will have contradictory information about the same user. This leads to data discrepancies in GA4 reporting and potential compliance issues. Verify both signals fire from the same consent event.

Debugging Toolkit

When things go wrong, these tools help:

  • Browser DevTools → Console: Run __tcfapi('ping', 2, console.log) and __tcfapi('getTCData', 2, console.log) to inspect live state.
  • IAB TC String decoder: Paste a TC String into a decoder to verify its contents match what you expect.
  • Network tab filtering: Search for gdpr_consent or consent in query parameters to verify the string is being passed in ad calls.
  • CookieBeam diagnostics: CookieBeam's dashboard shows TC String generation status, vendor list sync state, and consent mode signal mapping — all in one view.

How CookieBeam Handles TCF 2.2 Automatically

CookieBeam includes a full TCF 2.2 implementation that handles the spec's complexity for you. Here's what that means concretely:

  • Automatic GVL sync — CookieBeam fetches and caches the latest Global Vendor List daily. When IAB Europe publishes a new version, your consent UI updates automatically. No manual intervention needed.
  • TC String generation — every consent interaction produces a spec-compliant TC String including the core segment, DisclosedVendors (TCF 2.3 compliant), and publisher restrictions. The string is stored in the euconsent-v2 cookie and made available through the __tcfapi endpoint.
  • Publisher restrictions UI — configure restrictions per-purpose and per-vendor directly in the CookieBeam dashboard. No need to manually encode restriction segments.
  • Unified Consent Mode + TCF — a single banner drives both the TC String and Google Consent Mode signals. When a user consents to TCF Purpose 1, CookieBeam simultaneously grants ad_storage and analytics_storage. Purpose 3 maps to ad_user_data, Purpose 4 to ad_personalization. You don't configure this mapping — it's built in.
  • Script blocking — CookieBeam blocks vendor scripts until consent is confirmed, so there's no race condition between your CMP stub and vendor tags. Tags fire only after the TC String confirms the required purpose consent.
  • Audit trail — every consent event is logged server-side with the full TC String, timestamp, and user choices. This record satisfies GDPR's accountability requirement if a DPA asks you to demonstrate proof of consent.

Ready to Implement?

Getting TCF 2.2 right is mostly about getting the details right: load order, vendor list hygiene, publisher restrictions, and keeping TCF and Consent Mode in sync. A TCF-capable CMP like CookieBeam takes care of the encoding, the API, and the GVL management — you configure your vendor list and restrictions, and the rest happens automatically. Start with the TCF overview if you need the policy context, or check our TCF vs Consent Mode comparison if you're still sorting out which framework does what.

TCF 2.2 Implementation for Publishers: Complete Technical Walkthrough | CookieBeam | CookieBeam