IAB Europe Transparency & Consent Framework
Final v.2.2 May 2023
- Version History
- Introduction
- CMP API v2.0
- Using the CMP API
Date | Version | Comments |
---|---|---|
January 2024 | 2.2 | Added details for CTV support |
May 2023 | 2.2 | Update to further strengthen the TCF as a standard in the industry: Deprecated API command "getTCData". |
September 2021 | 2.0 | Deprecation of Global Scope and OOB |
February 2020 | 2.0 | Removed CMP List; added included in the Consent String and Vendor List Specification |
February 2020 | 2.0 | Updated stub example to reference open-source library, change addEventListener/removeEventListener interface, clarify addEventListener callback invocation time, and remove SafeFrame proxy communications |
December 2019 | 2.0 | Updated with reference to CMP List, Updated macros to be upper case, Added cmpStatus to be surfaced in both the API calls and the TCData object, and fixed case in a reference to IABTCF_CmpSdkID |
August 2019 | 2.0 | Final version released for adoption |
April 2019 | 2.0 | Released for public comment |
April 2018 | 1.1 | First version released to the public |
This document is one of the IAB Europe Transparency and Consent Framework (TCF) Specifications. It defines the API for Consent Management Providers (CMPs). The CMP API v2 is the interface a CMP provides for callers (web and in-app) to access information regarding the transparency and consent disclosed and obtained from the end user by the CMP. Both required functionality that the CMP must provide and optional features are described.
The General Data Protection Regulation (GDPR) requires a high level of accountability for how personal data is processed for users consuming content online or in-app. Specifically, GDPR requires a legal basis for such processing. Two of the legal bases described in the GDPR are the most relevant to organizations that operate in the digital advertising ecosystem. Such organizations need to either obtain consent from the user to process their personal data, or establish legitimate interests for processing data such that the interests and fundamental rights of the user are not overriding.
Under the GDPR, controllers are required to create and maintain records of compliance. While compliance is important, implementation came with heavy technical challenges. Clear standards for a common technical solution would be needed.
IAB Europe established the TCF to support compliance with the GDPR in the context of digital advertising. This framework is built on four components: a Global Vendor List (GVL), a Transparency and Consent String (TC String) to store data, an API for CMPs to create and process the TC String, and the Policies that govern how the TCF is used.
Prescribed use of the TCF establishes an audit trail to help maintain compliance with the GDPR, but the real benefit to the digital advertising ecosystem is a safer Internet for consumers, and more reliable data for brands and publishers. As adoption of the TCF increases, compliance becomes more scalable and data becomes more meaningful.
To participate in the use of the TCF, become familiar with the Policies for using it. To have transparency and consent established and signaled for your online services, apply to be added to the GVL. To play a role in creating a TC String for signaling status on transparency and user consent, sign up with IAB Europe to become a CMP. CMPs must follow technical standards provided in this document for creating TC Strings in compliance with TCF Policy. They must also follow technical standards for using the CMP API specified in this document to receive and process information provided in the TC String.
IAB Europe Transparency & Consent Framework (TCF) has a simple objective to help all parties in the digital advertising chain ensure that they comply with the EU’s General Data Protection Regulation and ePrivacy Directive when processing personal data or accessing and/or storing information on a user’s device, such as cookies, advertising identifiers, device identifiers and other tracking technologies. IAB Tech Lab stewards the development of these technical specifications.
Resources including policy FAQ, Global Vendor List, and CMP List can be found at iabeurope.eu/tcf.
IAB Europe Transparency and Consent Framework technical specifications governed by the IAB Tech Lab is licensed under a Creative Commons Attribution 3.0 License. To view a copy of this license, visit creativecommons.org/licenses/by/3.0/ or write to Creative Commons, 171 Second Street, Suite 300, San Francisco, CA 94105, USA.
THE STANDARDS, THE SPECIFICATIONS, THE MEASUREMENT GUIDELINES, AND ANY OTHER MATERIALS OR SERVICES PROVIDED TO OR USED BY YOU HEREUNDER (THE “PRODUCTS AND SERVICES”) ARE PROVIDED “AS IS” AND “AS AVAILABLE,” AND IAB TECHNOLOGY LABORATORY, INC. (“TECH LAB”) MAKES NO WARRANTY WITH RESPECT TO THE SAME AND HEREBY DISCLAIMS ANY AND ALL EXPRESS, IMPLIED, OR STATUTORY WARRANTIES, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AVAILABILITY, ERROR-FREE OR UNINTERRUPTED OPERATION, AND ANY WARRANTIES ARISING FROM A COURSE OF DEALING, COURSE OF PERFORMANCE, OR USAGE OF TRADE. TO THE EXTENT THAT TECH LAB MAY NOT AS A MATTER OF APPLICABLE LAW DISCLAIM ANY IMPLIED WARRANTY, THE SCOPE AND DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW. THE PRODUCTS AND SERVICES DO NOT CONSTITUTE BUSINESS OR LEGAL ADVICE. TECH LAB DOES NOT WARRANT THAT THE PRODUCTS AND SERVICES PROVIDED TO OR USED BY YOU HEREUNDER SHALL CAUSE YOU AND/OR YOUR PRODUCTS OR SERVICES TO BE IN COMPLIANCE WITH ANY APPLICABLE LAWS, REGULATIONS, OR SELF-REGULATORY FRAMEWORKS, AND YOU ARE SOLELY RESPONSIBLE FOR COMPLIANCE WITH THE SAME.
The IAB Technology Laboratory (Tech Lab) is a non-profit consortium that engages a member community globally to develop foundational technology and standards that enable growth and trust in the digital media ecosystem.. Comprised of digital publishers, ad technology firms, agencies, marketers, and other member companies, IAB Tech Lab focuses on improving the digital advertising supply chain, measurement, and consumer experiences, while promoting responsible use of data. Its work includes the OpenRTB real-time bidding protocol, ads.txt anti-fraud specification, Open Measurement SDK for viewability and verification, VAST video specification, and DigiTrust identity service. Board members include ExtremeReach, Facebook, Google, GroupM, Hearst Digital Media, Index Exchange, Integral Ad Science, LinkedIn, LiveRamp, MediaMath, Microsoft, Oracle Data Cloud, Pandora, PubMatic, Quantcast, Rakuten Marketing, Telaria, The Trade Desk, Verizon Media Group, Xandr, and Yahoo! Japan. Established in 2014, the IAB Tech Lab is headquartered in New York City with staff in San Francisco, Seattle, and London. Learn more at iabtechlab.com.
IAB Europe is the European-level association for the digital marketing and advertising ecosystem. Through its membership of National IABs and media, technology and marketing companies, its mission is to lead political representation and promote industry collaboration to deliver frameworks, standards and industry programmes that enable business to thrive in the European market.
Learn more about IAB Europe here: iabeurope.eu/
Consent Management Providers (CMPs) provide a user interface to establish transparency to users, and obtain consent or register objections from end users, and capture their preferences in Signals. These Signals are packaged in a standardized, easily-communicated payload called a TC String. The CMP API provides a standardized means for parties, such as the hosting publisher or an advertising vendor, to access these preferences managed by the CMP.
Using the API, scripts may obtain the TC String payload as well as the information it contains, which is ready to use without having to understand how to "unpack" the payload format. This makes it easy to make immediate data processing decisions based on the returned information.
CMPs may provide proprietary interfaces for specialised features or capabilities. The design and operation of a proprietary interface is documented in the IAB Europe Transparency and Consent Framework Policies.
This document specifies required functionality that the CMP must provide in accordance with the TCF. Any CMP functionality, including a publisher CMP or any UI and configuration, are provided by a designated CMP and using this CMP API. Other standardized APIs fall outside the TCF and may not be aligned to TCF policies.
The Global Vendor List (GVL) is a technical document that CMPs download from a domain managed by IAB Europe. It lists all registered and approved Vendors, as well as standard Purposes, Features, Special Purposes, Special Features, Stacks and Data Categories used in conjunction with purposes. The information stored in the GVL is used for determining what legal disclosures must be made to the user. IAB Europe manages and publishes the GVL.
See the ‘The Global Vendor List’ section in the ‘Consent string and vendor list formats v2’ spec which describes the content and the use of the global vendor list in detail.
Every consent manager MUST provide the following API function:
__tcfapi(command, version, callback, parameter)
The function __tcfapi
must always be a function and cannot be any other type, even if only temporarily on initialization – the API must be able to handle calls at all times.
Secondarily, CMPs must provide a proxy for postMessage events targeted to the __tcfapi
interface sent from within nested iframes. See the section on iframes for information.
All CMPs must support three required API commands: 'ping'
, 'addEventListener'
and 'removeEventListener'
.
Deprecated in TCF v2.2. Add an 'addEventListener'
and use its callback function to access the tcData object.
argument name | type | value |
---|---|---|
command | string | 'ping' |
version | number | 2 |
callback | function | function(pingReturn: PingReturn) |
Example:
__tcfapi('ping', 2, (pingReturn) => {
// do something with pingReturn
});
The ping command invokes the callback immediately without any asynchronous logic and returns a PingReturn
object for determining whether or not the main CMP script has loaded yet and whether GDPR applies; therefore, the only command required to be on the page in a stub before the rest of the commands are implemented. See the section "What does the gdprApplies value mean?" for more.
The callback
shall be invoked only once per api call with this command.
argument name | type | value |
---|---|---|
command | string | 'addEventListener' |
version | number | 2 |
callback | function | function(tcData: TCData, success: boolean) |
Example:
const callback = (tcData, success) => {
if(success && tcData.eventStatus === 'tcloaded') {
// do something with tcData.tcString
} else {
// do something else
}
}
__tcfapi('addEventListener', 2, callback);
Registers a callback function with a CMP (or a postmessage to respond to for cross-domain case). The callback will be invoked with the TCData
object as an argument whenever the TC String is changed and a new one is available. The TCData
object will contain CMP-assigned listenerId
for the registered listener. The eventStatus
property of the TCData
object shall be one of the following:
eventStatus | Description |
---|---|
'tcloaded' |
This shall be the value for the eventStatus property of the TCData object when a CMP is loaded and is prepared to surface a TC String to any calling scripts on the page. A CMP is only prepared to surface a TC String for this eventStatus if an existing, valid TC String is available to the CMP and it is not intending to surface the UI. If, however, the CMP will surface the UI because of an invalid TC String (e.g. it is too old, incorrect or does not reflect all the information the CMP needs to gather from the user) then an event with this eventStatus must not be triggered. |
'cmpuishown' |
This shall be the value for the eventStatus property of the TCData object any time the UI is surfaced or re-surfaced, a TC String is available and has rendered "Transparency" in accordance with the TCF Policy. The CMP shall create a TC string with all the surfaced vendors’ legitimate interest signals set to true and all the consent signals set to false. If previous TC signals are present a CMP may also merge those into the now-available TC String in accordance with the policy. |
'useractioncomplete' |
This shall be the value for the eventStatus property of the TCData object whenever a user has confirmed or re-confirmed their choices in accordance with TCF Policy and a CMP is prepared to respond to any calling scripts with the corresponding TC String. |
The CMP will, in most cases, invoke the callback when either the 'tcloaded'
OR 'cmpuishown'
+ 'useractioncomplete'
eventStatus
(s) occur, but never for all three eventStatuses
within the same page view. However, if an existing and valid TC string is available and the CMP does not intend to to surface a UI automatically ('tcloaded'
) but the user manually surfaces the UI and changes their selected choices ('cmpuishown'
+ 'useractioncomplete'
) all three eventStatuses
would appear within the same page view.
The callback shall be invoked with false
as the argument for the success
parameter if the callback could not be registered as a listener for any reason.
Note: The
addEventListener
callback shall be immediately called upon registration with the current TC data, even if the CMP status isloading
and the CMP has incomplete TC Data, so that the calling script may have access to its registeredlistenerId
. Furthermore, on every TC String change the callback shall be called unless it is removed viaremoveEventListener
.
argument name | type | value |
---|---|---|
command | string | 'removeEventListener' |
version | number | 2 |
callback | function | function(success: boolean) |
parameter | number | listenerId , the unique ID assigned by the CMP to the registered callback (via addEventListener ) |
Example: see 'addEventListener'
The callback shall be called with false
as the argument for the success
parameter if the listener could not be removed (e.g. the CMP cannot find a registered listener corresponding to listenerId
).
A CMP may choose to support two optional API commands: 'getInAppTCData'
and 'getVendorList'
.
argument name | type | value |
---|---|---|
command | string | 'getInAppTCData' |
version | number | 2 |
callback | function | function(inAppTCData: InAppTCData, success: boolean) |
Example:
__tcfapi('getInAppTCData', 2, (inAppTCData, success) => {
if(success) {
// do something with inAppTCData
} else {
// do something else
}
});
A mobile in-app CMP that uses a web-based UI in a mobile web view may choose to implement API calls with this command for the purpose of retrieving the TC String and pre-parsed TC signals from that web-based UI for the purpose of storing them in the NSUserDefaults
(iOS) or SharedPreferences
(Android). (see What is the CMP in-app internal structure for the defined API?)
The callback shall be invoked only once per api call with this command.
argument name | type | optional | value |
---|---|---|---|
command | string | 'getVendorList' |
|
version | number | 2 |
|
callback | function | function(gvl: GlobalVendorList, success: boolean) |
|
parameter | int or string | ✔️ | vendorListVersion |
Example:
__tcfapi('getVendorList', 2, (gvl, success) => {
if(success) {
// do something with gvl
} else {
// do something else
}
}, 'LATEST');
Calling with this command and a valid vendorListVersion
parameter shall return a GlobalVendorList
object to the callback
function. The caller may specify a Global Vendor List version number with the vendorListVersion
parameter. If no version is specified, the Global Vendor List version returned shall be the same as that which is encoded in the current TC String – If no TC String exists the latest version of the Global Vendor List shall be returned. The calling function may also pass 'LATEST'
as the argument to the vendorListVersion
parameter to explicitly receive the latest Global Vendor List version as the GlobalVendorList
object.
If an invalid vendorListVersion
argument is passed with the getVendorList
command the callback function shall receive a null
argument for the GlobalVendorList
parameter and the success
parameter shall receive a false
argument. Valid vendorListVersion
s are integers (or integer strings) greater than 1
. The success
parameter shall receive a false
argument for any unsuccessful call with the getVendorList
command. (eg. invalid vendorListVersion
argument, network error, etc…)
The callback shall be invoked only once per api call with this command.
This object contains both the encoded and unencoded values of the TC String as well as information about the CMP eventStatus
and whether or not GDPR applies to this user in this context (see the section "What does the gdprApplies value mean?" for more). If GDPR does not apply to this user in this context then only gdprApplies
, tcfPolicyVersion
, cmpId
and cmpVersion
shall exist in the object. If it is unknown just yet whether GDPR Applies to this user in this context or if this is CMP Stub code then the callback
shall not be invoked until that gdprApplies
is known.
TCData = {
tcString: 'base64url-encoded TC string with segments',
tcfPolicyVersion: 4,
cmpId:1000,
cmpVersion: 1000,
/**
* true - GDPR Applies
* false - GDPR Does not apply
* undefined - unknown whether GDPR Applies
* see the section: "What does the gdprApplies value mean?"
*/
gdprApplies: Boolean | undefined,
/*
* see addEventListener command
*/
eventStatus: String,
/**
* see Ping Status Codes in following table
*/
cmpStatus: 'string',
/**
* If this TCData is sent to the callback of addEventListener: number,
* the unique ID assigned by the CMP to the listener function registered
* via addEventListener.
* Others: undefined.
*/
listenerId: Number | undefined,
/*
* true - Default value
* false - TC String is invalid.
* since Sept 1st 2021, TC strings established with global-scope are considered invalid.
* see the section: ["What happened to Global Scope and Out of Band?"](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/TCF-Implementation-Guidelines.md#gsoob) in "IAB Europe Transparency and Consent Framework Implementation Guidelines"
*/
isServiceSpecific: Boolean,
/**
* true - CMP is using publisher-customized stack descriptions and/or modified or supplemented standard Illustrations
* false - CMP is NOT using publisher-customized stack descriptions and or modified or supplemented standard Illustrations
*/
useNonStandardTexts: Boolean,
/**
* Country code of the country that determines the legislation of
* reference. Normally corresponds to the country code of the country
* in which the publisher's business entity is established.
*/
publisherCC: 'Two-letter ISO 3166-1 alpha-2 code',
/**
*
* true - Purpose 1 not disclosed at all. CMPs use PublisherCC to
* indicate the publisher's country of establishment to help Vendors
* determine whether the vendor requires Purpose 1 consent.
*
* false - There is no special Purpose 1 treatment status. Purpose 1 was
* disclosed normally (consent) as expected by TCF Policy
*/
purposeOneTreatment: Boolean,
purpose: {
consents: {
/**
* true - Consent
* false | undefined - No Consent.
*/
'[purpose id]': Boolean
},
legitimateInterests: {
/**
* true - Legitimate Interest Established
* false | undefined - No Legitimate Interest Established
*/
'[purpose id]': Boolean
}
},
vendor: {
consents: {
/**
* true - Consent
* false | undefined - No Consent
*/
'[vendor id]': Boolean
},
legitimateInterests: {
/**
* true - Legitimate Interest Established
* false | undefined - No Legitimate Interest Established
*/
'[vendor id]': Boolean
}
},
specialFeatureOptins: {
/**
* true - Special Feature Opted Into
* false | undefined - Special Feature NOT Opted Into
*/
'[special feature id]': Boolean
},
publisher: {
consents: {
/**
* true - Consent
* false | undefined - No Consent
*/
'[purpose id]': Boolean
},
legitimateInterests: {
/**
* true - Legitimate Interest Established
* false | undefined - No Legitimate Interest Established
*/
'[purpose id]': Boolean
},
customPurpose: {
consents: {
/**
* true - Consent
* false | undefined - No Consent
*/
'[purpose id]': Boolean
},
legitimateInterests: {
/**
* true - Legitimate Interest Established
* false | undefined - No Legitimate Interest Established
*/
'[purpose id]': Boolean
},
},
restrictions: {
'[purpose id]': {
/**
* 0 - Not Allowed
* 1 - Require Consent
* 2 - Require Legitimate Interest
*/
'[vendor id]': 1
}
}
}
}
This object contains information about the loading status and configuration of the CMP.
PingReturn = {
/**
* true - GDPR Applies
* false - GDPR Does not apply
* undefined - unknown whether GDPR Applies
* see the section: "What does the gdprApplies value mean?"
*/
gdprApplies: Boolean | undefined,
/**
* true - CMP main script is loaded
* false - still running stub
*/
cmpLoaded: Boolean,
/**
* see Ping Status Codes in following table
*/
cmpStatus: String,
/**
* see Ping Status Codes in following table
*/
displayStatus: String,
/**
* version of the CMP API that is supported, e.g. "2.0"
*/
apiVersion: String,
/**
* CMPs own/internal version that is currently running
* undefined if still the stub
*/
cmpVersion: Number | undefined,
/**
* IAB Assigned CMP ID
* undefined if still the stub
*/
cmpId: Number | undefined,
/**
* Version of the GVL currently loaded by the CMP
* undefined if still the stub
*/
gvlVersion: Number | undefined,
/**
* Number of the supported TCF version
* undefined if still the stub
*/
tcfPolicyVersion: Number | undefined,
};
Note: cmpLoaded
must be set to true
if the main script is loaded and the stub interface is replaced, regardless of whether or not the user will see the UI or interact with it.
Status Code | Applicable for | Description |
---|---|---|
'stub' |
cmpStatus | CMP not yet loaded – stub still in place |
'loading' |
cmpStatus | DEPRECATED (this status is not distinct and will be removed in a future version) |
'loaded' |
cmpStatus | CMP is finished loading |
'error' |
cmpStatus | CMP is in an error state. A CMP shall not respond to any other API requests if this cmpStatus is present. A CMP may set this status if, for any reason, it is unable to perform the operations in compliance with the TCF. |
'visible' |
displayStatus | User interface is currently displayed |
'hidden' |
displayStatus | User interface is not yet or no longer displayed |
'disabled' |
displayStatus | User interface will not show (e.g. GDPR does not apply or TC data is current and does not need renewal) |
InAppTCData = {
tcString: 'base64url-encoded TC string with segments',
tcfPolicyVersion: 2,
cmpId:1000,
cmpVersion: 1000,
/**
* 1 - GDPR Applies
* 0 - GDPR Does not apply
* undefined - unknown whether GDPR applies
* see the section: "What does the gdprApplies value mean?"
*/
gdprApplies: 1,
/*
* see addEventListener command
*/
eventStatus: 'string',
/*
* 1 - Default value
* 0 - TC String is invalid.
* since Sept 1st 2021, TC strings established with global-scope are considered invalid.
* see the section: ["What happened to Global Scope and Out of Band?"](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/TCF-Implementation-Guidelines.md#gsoob) in "IAB Europe Transparency and Consent Framework Implementation Guidelines"
*/
isServiceSpecific: 1,
/**
* 1 - CMP is using publisher-customized stack descriptions and/or modified or supplemented standard Illustrations
* 0 - CMP is NOT using publisher-customized stack descriptions and/or modified or supplemented standard Illustrations
*/
useNonStandardTexts: 1,
/**
* Country code of the country that determines the legislation of
* reference. Normally corresponds to the country code of the country
* in which the publisher's business entity is established.
*/
publisherCC: 'Two-letter ISO 3166-1 alpha-2 code',
/**
* 1 - Purpose 1 not disclosed at all. CMPs use PublisherCC to indicate
* the publisher's country of establishment to help vVendors determine
* whether the vendor requires Purpose 1 consent.
*
* 0 - There is no special Purpose 1 treatment status. Purpose 1 was
* disclosed normally (consent) as expected by TCF Policy.
*/
purposeOneTreatment: 1,
purpose: {
/**
* 1 - Consent
* 0 | undefined - No Consent
*/
consents: '01010 -- Purpose bitfield',
/**
* 1 - Legitimate Interest Established
* 0 | undefined - No Legitimate Interest Established
*/
legitimateInterests: '01010 -- Purpose bitfield'
},
vendor: {
/**
* 1 - Consent
* 0 | undefined - No Consent
*/
consents: '01010 -- Vendor bitfield',
/**
* 1 - Legitimate Interest Established
* 0 | undefined - No Legitimate Interest Established
*/
legitimateInterests: '01010 -- Vendor bitfield'
},
/**
* 1 - Special Feature Opted Into
* 0 | undefined - Special Feature NOT Opted Into
*/
specialFeatureOptins: '01010 -- Special Feature bitfield',
publisher: {
/**
* 1 - Consent
* 0 | undefined - No Consent
*/
consents: '01010 -- Purpose bitfield',
/**
* 1 - Legitimate Interest Established
* 0 | undefined - No Legitimate Interest Established
*/
legitimateInterests: '01010 -- Purpose bitfield',
customPurpose: {
/**
* 1 - Consent
* 0 | undefined - No Consent
*/
consents: '01010 -- Purpose bitfield',
/**
* 1 - Legitimate Interest Established
* 0 | undefined - No Legitimate Interest Established
*/
legitimateInterests: '01010 -- Purpose bitfield'
},
restrictions: {
/**
* 0 - Not Allowed
* 1 - Require Consent
* 2 - Require Legitimate Interest
* _ - No Restriction (maintains indexing)
*
* each position represents vendor id and number represents restriction
* type 0-2
*/
'[purpose id]': '01201221'
}
}
}
The steps for integrating a CMP SDK into an app are the following:
- An app publisher should embed a CMP SDK – The setup and configuration as well as the protocol for how to initialize the CMP SDK are all proprietary to each CMP SDK.
- Since more than one CMP SDK may be included in publishers' linked SDKs, the publisher must initialize only one of them. The initialized CMP shall set
IABTCF_CmpSdkID
with its ID as soon as it is initialized in the app to signal to vendors that a CMP is present. - The CMP SDK will determine if GDPR applies (see the section "What does the gdprApplies value mean?") to this user in this context. But, a publisher may choose to initialize a CMP dialogue UI manually.
- The CMP shall set the
NSUserDefaults
(iOS) orSharedPreferences
(Android) variables and vendors will then be able to read from them directly. - Vendors should listen to
IABTCF_*
key updates to retrieve new TC data fromNSUserDefaults
(iOS) orSharedPreferences
(Android).
NSUserDefaults
(iOS) or SharedPreferences
(Android) shall be used to store pre-parsed TC data as well as the TC string by a CMP SDK. It allows:
- Vendors to easily access TC data
- TC data to persist across app sessions
- TC data to be portable between CMPs to provide flexibility for a publisher to exchange one CMP SDK for another
- Vendors within an app to avoid code duplication by not being required to include a TC string decoder while still enabling all typical use cases
Note: If a publisher chooses to remove a CMP SDK from their app they are responsible for clearing all IABTCF_*
vestigial values for users so that vendors do not continue to use the TC data therein.
NSUserDefaults
(iOS) or SharedPreferences
(Android) values
Key | Value(s) |
---|---|
IABTCF_CmpSdkID |
Number : The unsigned integer ID of CMP SDK |
IABTCF_CmpSdkVersion |
Number : The unsigned integer version number of CMP SDK |
IABTCF_PolicyVersion |
Number : The unsigned integer representing the version of the TCF that these consents adhere to. |
IABTCF_gdprApplies |
Number :
Unset - undetermined (default before initialization) see the section "What does the gdprApplies value mean?" for more |
IABTCF_PublisherCC |
String : Two-letter ISO 3166-1 alpha-2 code – Default: AA (unknown) |
IABTCF_PurposeOneTreatment |
Number :
Unset default - Vendors can use this value to determine whether consent for purpose one is required. |
IABTCF_UseNonStandardTexts |
Number :
|
IABTCF_TCString |
String : Full encoded TC string |
IABTCF_VendorConsents |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the consent status for Vendor ID n+1; false and true respectively. eg. '1' at index 0 is consent true for vendor ID 1 |
IABTCF_VendorLegitimateInterests |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the legitimate interest status for Vendor ID n+1; false and true respectively. eg. '1' at index 0 is legitimate interest established true for vendor ID 1 |
IABTCF_PurposeConsents |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the consent status for purpose ID n+1; false and true respectively. eg. '1' at index 0 is consent true for purpose ID 1 |
IABTCF_PurposeLegitimateInterests |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the legitimate interest status for purpose ID n+1; false and true respectively. eg. '1' at index 0 is legitimate interest established true for purpose ID 1 |
IABTCF_SpecialFeaturesOptIns |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the opt-in status for special feature ID n+1; false and true respectively. eg. '1' at index 0 is opt-in true for special feature ID 1 |
IABTCF_PublisherRestrictions{ID} |
String ['0','1', or '2'] : The value at position n – where n's indexing begins at 0 – indicates the publisher restriction type (0-2) for vendor n+1; (see Publisher Restrictions Types). eg. '2' at index 0 is restrictionType 2 for vendor ID 1 . {ID} refers to the purpose ID. |
IABTCF_PublisherConsent |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the purpose consent status for purpose ID n+1 for the publisher as they correspond to the Global Vendor List Purposes; false and true respectively. eg. '1' at index 0 is consent true for purpose ID 1 |
IABTCF_PublisherLegitimateInterests |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the purpose legitimate interest status for purpose ID n+1 for the publisher as they correspond to the Global Vendor List Purposes; false and true respectively. eg. '1' at index 0 is legitimate interest established true for purpose ID 1 |
IABTCF_PublisherCustomPurposesConsents |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the purpose consent status for the publisher's custom purpose ID n+1 for the publisher; false and true respectively. eg. '1' at index 0 is consent true for custom purpose ID 1 |
IABTCF_PublisherCustomPurposesLegitimateInterests |
Binary String : The '0' or '1' at position n – where n's indexing begins at 0 – indicates the purpose legitimate interest status for the publisher's custom purpose ID n+1 for the publisher; false and true respectively. eg. '1' at index 0 is legitimate interest established true for custom purpose ID 1 |
On both Android OS and iOS, the vendor can get notified when the values of the shared keys change. See NSUserDefaultsDidChangeNotification and SharedPreferences.OnSharedPreferenceChangeListener.
On Android OS, the TC data and TC string shall be stored in the default Shared Preferences for the application context. This can be accessed using the getDefaultSharedPreferences
method from the android.preference.PreferenceManager
class using the application context.
Example:
Context mContext = getApplicationContext();
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
The TC data values can be retrieved from the application Shared Preferences by key name using the get
methods on the android.content.SharedPreferences
class. For the purposes of accessing TC data, only two methods should be necessary: getString(String key, String defValue)
for String
values and getInt(String key, int defValue)
for integer
s and integer
representations of Boolean
values.
Example:
Context mContext = getApplicationContext();
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
String consentString = mPreferences.getString("IABTCF_TCString", "");
int gdprApplies = mPreferences.getInt("IABTCF_gdprApplies", 0);
A callback can be registered to update settings when a preference is changed using the registerOnSharedPreferenceChangeListener
method for the android.content.SharedPreferences
class.
Note: The preference manager does not currently store a strong reference to the listener. If you do not store a strong reference, the listener will be susceptible to garbage collection. External guidance such as this documentation on setting listeners may provide more information on listening for preference changes.
Example:
Context mContext = getApplicationContext();
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.OnSharedPreferenceChangeListener mListener;
mListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (key.equals([Specific Consent Key])) {
// Update Consent settings
}
}
};
mPreferences.registerOnSharedPreferenceChangeListener(mListener);
Mediation SDK allows app developers to monetize from multiple vendors.
- Mediation SDK retrieves
IABTCF_gdprApplies
andIABTCF_TCString
fromNSUserDefaults
(iOS) orSharedPreferences
(Android). - If
IABTCF_gdprApplies == 0
, Mediation SDK can run mediation across all ad network SDKs. - If
IABTCF_gdprApplies == 1
, Mediation SDK will run mediation only among the ad network SDKs that are GDPR ready.
'GDPR ready' means that the vendor retrieves IABTCF_gdprApplies
and IABTCF_TCString
from NSUserDefaults
(iOS) or SharedPreferences
(Android), and passes on these GDPR values downstream.
- Vendor retrieves
IABTCF_gdprApplies
andIABTCF_TCString
fromNSUserDefaults
(iOS) orSharedPreferences
(Android), and passes on these GDPR values downstream.
The context of the CTV application will determine the storage locations and naming of the TCF data.
Applications running in a web runtime environment that supports, at minimum, the Web Storage (Second Edition) specification shall follow all storage and naming conventions detailed in the Javascript section of this spec. Data is to be retrieved using the commands, offering a consistent interface for Vendors to access TC string information.
Should data not persist in Web Storage beyond the lifecycle of the application (application close, standby, or device shutdown), all data storage and naming conventions are to follow the specifications outlined in the CTV Native Private Storage section of this spec.
Native CTV applications should support both Global Privacy Platform (GPP) section key names as well as TCF key names by following the naming conventions of Global Privacy Platform (GPP) data and string outlined in the TCF EU Section spec and the TCF naming conventions outlined for in-app usage above. Data is to be limited to the context of the Application and inaccessible to external applications.
Application Preferences (Registry)
Application Preferences, also referred to as a Registry in certain CTV environments, shall be used in a Native CTV Application environment under the condition that the TC data and TC String fit within the device constraints. Private Storage is to be used if the TC data and TC String do not fit within the device constraints
Private Storage
Private Storage shall be used under the condition that the CTV environment does not offer a Web Runtime that supports the Web Storage (Second Edition) specification, data does not persist beyond the lifecycle of the Application, or offer an Application Preferences (Registry) interface. The TC data and TC String are to be saved in a standardized and private storage space. Files are to follow the same naming convention as the key names detailed in the TCF EU Section spec and the key names outlined for in-app usage above with the contents being the value of the corresponding key. Note: CTV Applications require proper permission scopes to be configured to read and write to the virtual Application file system.
Android TV
// Option 1
public void setTCString(String tcString) {
SharedPreferences.Editor editor = sharedPrefs.edit();
// TCF spec
editor.putString("IABTCF_TCString", tcString);
// GPP spec
editor.putString("IABGPP_2_TCString", tcString);
editor.commit();
}
// Option 2
public void setTCString(String tcString) {
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString("IABTCF_TCString", tcString);
editor.commit();
}
public void setTCStringForGpp(String tcString) {
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString("IABGPP_2_TCString", tcString);
editor.commit();
}
Apple TV
// Option 1
- (void)setTcString:(NSString *)tcString {
NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults;
// TCF spec
[userDefaults setObject:tcString forKey:@"IABTCF_TCString"];
// GPP spec
[userDefaults setObject:tcString forKey:@"IABGPP_2_TCString"];
}
// Option 2
- (void)setTcString:(NSString *)tcString[INSERT] {
NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults;
[userDefaults setObject:tcString forKey:@"IABTCF_TCString"];
}
- (void)setTcStringForGpp:(NSString *)tcString[INSERT] {
NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults;
[userDefaults setObject:tcString forKey:@"IABGPP_2_TCString"];
Roku Reference
Function SetTcfData(tcString As String) As Void
sec = CreateObject("roRegistrySection", "TCF")
sec.Write("IABTCF_TCString", tcString)
sec.Flush()
End Function
Function SetGppData(tcString As String) As Void
sec = CreateObject("roRegistrySection", "GPP")
sec.Write("IABGPP_2_TCString", tcString)
sec.Flush()
End Function
The following details provide information about how ad tags work, using the version parameter in the __tcfapi()
function, and how vendors can interact with the API.
Tag-based demand, especially ad tags, are basically creative files, that are not an advertisement themselves, but are loaded to access additional sources to provide ad creative.
For performance reasons, the preferred way to make this happen in current ad servers are macros. The following two macros are recommended for ad server implementation:
Macro | Values |
---|---|
${GDPR} |
1 - GDPR Applies 0 - GDPR does not apply unset - unknown |
${GDPR_CONSENT_XXXX} |
Encoded TC String where XXXX is the numeric Vendor ID of the vendor receiving the TC string. |
Note: Values align with IAB OpenRTB GDPR Advisory
Note: For more information on GDPR Applies see the section "What does the gdprApplies value mean?"
The Version
parameter of the API is used to enable scripts to specify what version of the API they are prepared to handle. The CMP shall respond in kind with the appropriately versioned information, if available.
If the argument is 0
(Zero), null
or undefined
, the CMP shall return the information for the latest (highest) version available. For example, when a user has a v2 TC string and a v3 TC string, the CMP should return the v3 TC string and TC data.
If the argument is invalid (i.e. not a positive integer greater than 1
or higher than the highest supported version for this CMP) the CMP shall invoke the callback with an argument of false
for the success parameter and a null
argument for any expected TC data parameter.
If the argument is 1
, the CMP shall invoke the callback with an argument of false
for the success parameter and a null
argument for any expected TC data parameter, as this TCF version is no longer supported by this API.
If the argument is an integer higher than 1
, the CMP shall invoke the callback with defined data according to the specified version if it exists in that version. For obvious reasons, if new properties of the version-specific outlined TC data objects are added in v3, a v2 TC data object shall not contain these new properties because they may either not exist or may have different meaning from version to version.
gdprApplies
is a boolean
value that may be undefined
. A CMP shall determine whether or not GDPR applies in its current context and set the gdprApplies
value. A publisher may determine that GDPR applies to all traffic on their site and signal their CMP to always return true
for gdprApplies
, a CMP may invoke a geo-tagging service call to make a determination on a specific user or may have some other proprietary solution for determining whether or not GDPR applies in accordance with TCF Policy. In any case, vendors shall respect the value of gdprApplies
put forth by the CMP. If gdprApplies
value is undefined
but exists in the schema outlined in the response object in this document, then calling scripts shall assume that the CMP is still pending a determination on whether or not GDPR applies in this context. Note: For mobile all booleans are written as Number
(integer).
Scripts can check for the presence of a function named __tcfapi
– if it exists then a CMP can be assumed to be present for scripts. In iframes, the presence of a CMP can be determined by the existence of a specially-named iframe named "__tcfapiLocator"
in the parent (or above) frame. The CMP shall create an iframe as a signal to scripts nested in other iframes that a CMP exists in a higher frame and name it "__tcfapiLocator"
on the current DOM
to indicate its own presence; since iframe properties can be accessed from other iframes. Publishers must load the CMP in a parent (or ancestor) of all iframes that may need to establish a GDPR legal basis.
If a CMP is not present, or if the CMP fails to respond, vendors should assume "no consent" and “no legitimate interest transparency established” in contexts where GDPR applies (see the section "What does the gdprApplies value mean?" for more).
Typically, scripts will not need to check if the CMP script is loaded. Scripts can simply call the __tcfapi
function as it will queue the calls for execution when the full CMP script is loaded. If the full CMP has been loaded, its __tcfapi
implementation will handle the call normally. If necessary, the 'ping'
command will return a PingReturn
object that contains the boolean
property cmpLoaded
to indicate whether the cmp is loaded.
- A CMP-provided synchronous "stub" script must be added by the publisher to their page before any other scripts that rely on
__tcfapi
(this usually means between the<head></head>
tags of the HTML document). - This "stub" will:
- Define a queuing function named
__tcfapi
at theWindow
scope. - All arguments for a given call to the stubbed
__tcfapi
method will be enqueued as a set. - Define the postMessage handler function for cross-origin iframe requests.
- Add the newly-created
postMessage
handler function as an event listener on theWindow
object listening for the‘message’
event. - Create an iframe named
'__tcfapiLocator'
in the current DOM.
- Define a queuing function named
- When the main CMP implementation script loads and executes, it will:
- Create an internal reference to the queued argument sets of the "stub".
- Redefine the
__tcfapi
function to the CMP’s full API implementation. - Iterate and dequeue the queued argument sets in a first-in-first-out (FIFO) order and
apply
each set of arguments to the fully-implemented__tcfapi
function.
A CMP must provide stub script to its clients that at least supports the following features/logic:
__tcfapi
function that supports the ping command, with the minimum properties ofcmpLoaded
andapiVersion
. Note:gdprApplies
may also be set in thePingReturn
object if the "stub" is set by the publisher to apply GDPR to all traffic. However,gdprApplies
may not be available until the CMP is finished loading and the value will, therefore, beundefined
. See the section "What does the gdprApplies value mean?" for more.- Collect all calls to
__tcfapi
that cannot (yet) be handled by the “stub” in a queue - Check if
window.frames['__tcfapiLocator']
exists, indicating that a CMP is already present, otherwise create an empty iframe named'__tcfapiLocator'
in the current DOM. - Create an event listener for
postMessage
events on theWindow
object. When the event handler function receives a postMessage (‘message’
) event it shall proxy the__tcfapi
function requests to send the response back through thepostMessage
event channel - The stub code must be loaded and executed synchronously before any other scripts that depend on the
__tcfapi
function to be there – this usually means between the<head></head>
tags of the HTML document – in order to ensure that it can be executed before all calls from third parties.
You can find an iab-supported open-source implementation of the stub API here: https://github.com/InteractiveAdvertisingBureau/iabtcf-es/blob/master/modules/stub/
This code should be executed on the page before any other scripts that require the __tcfapi
function – this usually means between the <head></head>
tags of the HTML document. The sample script also includes the postMessage
handler.
The only way to request TC Data from a parent or ancestor’s frame is using postmessage.
The window.postMessage()
method may be used from a child iframe to make requests from a parent or any ancestor frame's CMP API. To locate an ancestor frame capable of responding to postMessage()
CMP API calls, search for an ancestor frame that has a child frame named '__tcfapiLocator'
(see sample code).
CMPs shall create an event listener to handle postMessage
requests via the CMP “stub” API script so that postMessage
events can be queued and processed by the full-implementation of the CMP API as soon as it is initialized.
Sent Message
The sent message shall follow the form outlined below. The command, parameter and version object properties correspond to their namesake parameters defined as method argument parameters for __tcfapi()
method. The “sent message” also requires a unique callId property to help match the request with a response. The callId
property shall be either a string or a number, but the calling script shall not use the two types interchangeably.
{
__tcfapiCall: {
command: "command",
parameter: parameter,
version: version
}
}
The event.data
object payload shall follow the form outlined below. The returnValue
object property shall be the corresponding TC data object for the command
used upon sending the “sent message”. The success
object property shall reflect the __tcfapi()
success
callback argument and the callId
will correspond to the “sent message” unique id passed in the callId
property.
{
__tcfapiReturn: {
returnValue: returnValue,
success: boolean,
callId: uniqueId
}
}
Below is an example script that emulates the in-frame __tcfapi()
call. It locates the ancestor frame running the CMP, performs the postMessage
and listens for the return message and passes its values to the callback:
(function() {
//start here at our window
let frame = window;
// if we locate the CMP iframe we will reference it with this
let cmpFrame;
// map of calls
const cmpCallbacks = {};
while(frame) {
try {
/**
* throws a reference error if no frames exist
*/
if (frame.frames['__tcfapiLocator']) {
cmpFrame = frame;
break;
}
} catch(ignore) {}
if(frame === window.top) {
break;
}
frame = frame.parent;
}
/**
* Set up a __tcfapi proxy method to do the postMessage and map the callback.
* From the caller's perspective, this function behaves identically to the
* CMP API's __tcfapi call
*/
window.__tcfapi = function(cmd, version, callback, arg) {
if (!cmpFrame) {
callback({msg: 'CMP not found'}, false);
} else {
const callId = Math.random() + '';
const msg = {
__tcfapiCall: {
command: cmd,
parameter: arg,
version: version,
callId: callId,
},
};
/**
* map the callback for lookup on response
*/
cmpCallbacks[callId] = callback;
cmpFrame.postMessage(msg, '*');
}
};
function postMessageHandler(event) {
/**
* when we get the return message, call the mapped callback
*/
let json = {};
try {
/**
* if this isn't valid JSON then this will throw an error
*/
json = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
} catch (ignore) {}
const payload = json.__tcfapiReturn;
if (payload) {
/**
* messages we care about will have a payload
*/
if (typeof cmpCallbacks[payload.callId] === 'function') {
/**
* call the mapped callback and then remove the reference
*/
cmpCallbacks[payload.callId](payload.returnValue, payload.success);
cmpCallbacks[payload.callId] = null;
}
}
}
window.addEventListener('message', postMessageHandler, false);
}());
__tcfapi('ping', 2, (pingReturn, success) => {
// should get response from window.top's CMP
});
See the ‘How should the transparency & consent string be stored?’ section in the ‘Transparency & Consent String and Global Vendor List Format’ spec which describes where CMPs must store the transparency & consent string.
- Deprecated command
getTCData
- Added
getInAppTCData
- Added properties to
PingReturn
- Added
addEventListener
- Added
TCData
- Removed
VendorConsents
- Removed
VendorConsentData
- Changed
getVendorConsents
togetTCData
- Renamed
__cmp
to__tcfapi
- Renamed all
__cmp*
to__tcfapi*
(e.g.__cmpLocator
is now__tcfapiLocator
) - Removed
getConsentData
andgetPublisherConsents
commands (data moved togetTCData
) - Added in-app API details throughout where applicable
- Removed SafeFrame proxy communication