27 October 2026 · 9 min read

TCF and GPP: What the Consent String Actually Controls

A consent management platform advertises TCF and GPP support. Two weeks later the GA4 property shows almost no traffic from EEA visitors who accepted analytics, and full collection from visitors who rejected everything. Both failures usually come from the same wrong assumption: that a consent string is a consent switch for every tag on the page.

It is not. A TC string records a user's choices per vendor and per purpose. What a tag does with that record is separate code, written by whoever built the tag. For Google tags that code exists and it is narrow. Knowing exactly how narrow is the difference between a defensible setup and a broken one.

Two strings, two jobs

The Transparency and Consent Framework comes from IAB Europe. The policies in force carry version 2026-05-29.5.0.b, and they state the obvious priority: where the law and the policies disagree, the law wins. The framework exists to help publishers and vendors meet ePrivacy and GDPR obligations, and the same document says it also serves the UK GDPR and PECR to the extent those stay aligned with the EU rules.

The Global Privacy Protocol comes from IAB Tech Lab. IAB Tech Lab renamed it from the Global Privacy Platform, and the older name still appears in most CMP documentation. It does not replace TCF. It is a transport layer for privacy signals across several jurisdictions, and it carries a TC string as one of its sections rather than instead of it.

Mechanically a GPP string is a header, then sections joined by tildes. The header encodes which section IDs follow. DBABM means one section, EU TCF v2, section ID 2. DBACNY means two sections, EU TCF v2 plus US Privacy, section ID 6. A full string looks like DBACNY~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN, where the middle block is the TC string itself.

What Google reads out of a TC string

Google documents six purpose mappings for its web tags. Read the table as a whole, because the shape of it is the point.

If Purpose 1, store and/or access information on a device, is denied, Google sets ad_storage and ad_user_data to denied. Deny Purpose 3 or 4, building a personalised ads profile and selecting personalised ads, and ad_personalization goes to denied. Purposes 7, 9 and 10 do not touch a consent signal at all. They disable Google Signals in Analytics, and only for web tags.

That is the entire map. Three consent signals and one reporting feature. There is no line for analytics_storage. Google's own implementation page closes the question in one sentence: to control Google Analytics cookies, integrate with consent mode. TCF integration is an advertising path.

The switch that turns the mapping on is easy to miss. It is either enableAdvertiserConsentMode set to true in the TCData objects your CMP publishes, or window['gtag_enable_tcf_support'] = true on each page, including pages loaded in an iframe. Apps carry their own flags, an Android manifest metadata entry and an iOS plist key, and a CMP can enable the integration there without anyone deciding to.

The 500 millisecond cliff

Google tags wait for the CMP API. If it does not respond within 500 milliseconds, or if the status comes back as loading, stub or error, the tag does not treat that as a refusal. It proceeds with your default consent settings.

Ad Manager's troubleshooting guide describes the same event from the ad side as error 2.1a: no TC string arrives because the CMP is still loading, stubbed or errored. The other codes are worth knowing because they all end in limited ads. A string that is not base64 encoded is 2.2a. A CMP ID that is not IAB validated is 3.1. A globally scoped string, or one allowing out of band consent, is 5.1 or 5.2. A v1 string is 6.1.

The practical consequence is that a slow CMP does not produce "no consent". It produces "whatever defaults your site declared". If those defaults are granted for advertising, the visitor who never saw a banner gets advertising cookies, and the audit trail points at the CMP whose only fault was taking 700 milliseconds to initialise.

Purpose 1 is the door

Purpose 1 is the only purpose that gates storage. Denied, and Google will not read or write its advertising cookies. Because it is a consent purpose, legitimate interest is not available for it, and since TCF v2.2 legitimate interest is not available for purposes 3 to 6 either.

Google's error 1.2 names the regions where a missing Purpose 1 consent blocks ads: EEA countries, the UK and Switzerland. There is a flag called Purpose One Treatment that lets a publisher declare consent for Purpose 1 is not required in its country. Google supports it for Switzerland only, and only with the publisher country code set to CH.

So for UK traffic the single bit that decides ad_storage is the Purpose 1 choice. A banner that clears purposes 3 and 4 on reject but leaves Purpose 1 granted will keep advertising cookies readable while looking correct in the interface. Nothing in a tag audit flags that, because the tag is doing exactly what the string says.

Who "Google" is in the string

Google appears as a vendor with ID 755, listed as Google Advertising Products. For ads to serve normally the string has to grant consent and establish legitimate interest on the purposes Google relies on, which is why a banner that only handles consent leaves half the requirement unmet.

TCF v2.3 added a disclosed vendors segment, and Google treats a missing or malformed segment as error 1.4, or as an omission when Google is absent from it. Google states that v2.3 is mandatory for all TC strings generated on or after 1 March 2026. Related failure 4.1 covers strings built against a GVL version that predates Google's listing, and the fix there is fresh consent rather than a code change.

Two checks follow. Does the CMP's vendor configuration include 755 for the purposes you rely on, and does the string carry v2.3? A yes to the first and no to the second is a common state, because the vendor list is configured once and the spec version moves underneath it.

The additional consent string, where smaller vendors live

Vendors not registered on the Global Vendor List cannot appear in a TC string. Google's answer is a second string, the additional consent string, written in ACv2 format. A value like 2~1.35.41.101~dv.9.21.81 reads as version 2, then the consented ad tech provider IDs, then the disclosed IDs after dv.

Only an IAB registered CMP may create it, using its own CMP ID, and only alongside a TC string. Google discards an AC string if no TC string arrives for the same request. Google also checks the GVL version named in the TC string and ignores AC entries for vendors registered there, so the two lists cannot be used to double count.

It travels as the addtl_consent URL parameter, or the ${ADDTL_CONSENT} macro inside a pixel URL. If a measurement partner you rely on sits outside the GVL, this string is the only place its consent exists.

GPP, and the six sections Google accepts

Google Ad Manager supports GPP for US state privacy laws, and states plainly that using GPP is not a requirement under those laws. It then narrows what it will read: US National, California, Colorado, Connecticut, Florida and Virginia strings only. Canada TCF, the US Privacy String, the Utah state string and IAB Europe TCF are not accepted as part of GPP support.

That last exclusion matters for architecture. The TC string stays the EU and UK carrier even where a CMP offers GPP, and a GPP string is the US state carrier where the law and the CMP support it. Two strings, two jurisdictions, one banner.

On a request the values appear as gpp and gpp_sid. The second one names which section is in force for that transaction, and it can hold up to two comma separated values when a single one cannot be determined. A section the callee does not accept is not a section it reads.

The UK wrinkle

PECR governs storage and access on a UK device. The ICO finalised its guidance on storage and access technologies on 29 April 2026, after two consultations, and it keeps the position that advertising needs consent while advertising measurement rides on that same consent rather than needing a second one. The statistical purposes exception survives, with conditions: clear information, and a simple means of objecting, free of charge.

None of that changes the mapping above, and that is the awkward part. analytics_storage is governed by your banner and your consent mode implementation, not by any purpose in the string. A UK site can be fully TCF compliant and still be collecting analytics without a valid choice, because the two systems were never joined up.

A test you can run in twenty minutes

Three checks, in this order, on a page served in the EEA or the UK.

window.gtag_enable_tcf_support
__tcfapi('getTCData', 2, function (data, ok) { console.log(ok, data.tcString, data.purpose, data.vendor); });
__gpp('getGPPData', function (data, ok) { console.log(ok, data.gppString, data.applicableSections); });

The first line tells you whether the Google tag is in TCF mode at all. Undefined means the integration was never switched on, and everything downstream is guessing. The second prints the purposes and vendor consents your CMP is publishing. The third shows whether a GPP string exists and which sections the CMP says apply.

Then open Tag Assistant on that page and read the consent tab. It should show ad_storage, ad_user_data, ad_personalization and analytics_storage, and the values should match what the banner recorded. If analytics_storage reads granted while the banner recorded a refusal, the missing link is your own consent default or update call, not the string.

Last check, in DebugView. Take a session from a country in scope, refuse analytics, and confirm no page_view appears. If one does, the analytics stream is running outside consent mode, and no amount of TCF configuration will fix that.

What goes in the audit

Three lines per property, and they are worth more than a screenshot of a banner. Which string the CMP produces, and which version. Which consent signals Google derives from it. Which signals it does not touch, and what governs those instead.

Put the purpose map in the report as a table, quote the default consent snippet next to it, and state in one sentence that TCF never sets analytics_storage. That sentence resolves most of the argument between a marketing team that believes the banner covers everything and an analytics team that can see it does not.

The rest is maintenance. CMP vendor lists change, GVL versions move, and a string that validated in February can trip error 4.1 by June. Put the version check on the same quarterly list as the tag audit, and the compliance story stops depending on a settings screen nobody opens.

If you cannot say which consent signals your tags actually receive, book a free tracking audit and we will read the strings on a live page with you, then check the GA4 side against them.