Skip to content

Latest commit

 

History

History
1148 lines (840 loc) · 61.7 KB

IAB Tech Lab - CMP API v2.md

File metadata and controls

1148 lines (840 loc) · 61.7 KB

iab tech lab

Consent Management Platform API

IAB Europe Transparency & Consent Framework

Final v.2.2 May 2023

Version History

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

Introduction

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.

About the Transparency & Consent Framework

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.

License

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.

Disclaimer

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.

About IAB Tech Lab

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.

About IAB Europe

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/

CMP API v2.0

What does the CMP API support?

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.

What is the Global Vendor List?

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.

How does the CMP provide the API?

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.

What required API commands must a CMP support?

All CMPs must support three required API commands: 'ping', 'addEventListener' and 'removeEventListener'.


getTCData

Deprecated in TCF v2.2. Add an 'addEventListener' and use its callback function to access the tcData object.


ping

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.


addEventListener

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 is loading and the CMP has incomplete TC Data, so that the calling script may have access to its registered listenerId. Furthermore, on every TC String change the callback shall be called unless it is removed via removeEventListener.


removeEventListener

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).


What optional API commands might a CMP support?

A CMP may choose to support two optional API commands: 'getInAppTCData' and 'getVendorList'.


getInAppTCData

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.


getVendorList

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 vendorListVersions 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.


What objects are returned from the API?


TCData

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
      }
    }
  }
}

PingReturn

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.

Ping Status Codes

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

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'
    }
  }
}

In-App Details

How is a CMP used in-app?

The steps for integrating a CMP SDK into an app are the following:

  1. 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.
  2. 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.
  3. 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.
  4. The CMP shall set the NSUserDefaults(iOS) or SharedPreferences(Android) variables and vendors will then be able to read from them directly.
  5. Vendors should listen to IABTCF_* key updates to retrieve new TC data from NSUserDefaults(iOS) or SharedPreferences(Android).

What is the CMP in-app internal structure for the defined API?

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:

1 GDPR applies in current context

0 - GDPR does not apply in current context

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:

0 - no special treatment of purpose one

1 - purpose one not disclosed

Unset default - 0

Vendors can use this value to determine whether consent for purpose one is required.

IABTCF_UseNonStandardTexts Number:

1 - CMP uses customized stack descriptions and/or modified or supplemented standard Illustrations

0 - CMP did not use a non-standard stack desc. and/or modified or supplemented Illustrations

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

How do third-party SDKs (vendors) access the consent information in-app?

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 integers 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);

How does ad mediation work in-app?

Mediation SDK allows app developers to monetize from multiple vendors.

Mediation SDK
  • Mediation SDK retrieves IABTCF_gdprApplies and IABTCF_TCString from NSUserDefaults(iOS) or SharedPreferences(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
  • Vendor retrieves IABTCF_gdprApplies and IABTCF_TCString from NSUserDefaults(iOS) or SharedPreferences(Android), and passes on these GDPR values downstream.

CTV Details

How is a CMP used in the CTV context?

The context of the CTV application will determine the storage locations and naming of the TCF data.

Web Runtime

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

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.

CTV Examples

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

Using the CMP API

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.

How do ad tags work?

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?"

How does the "version" parameter work?

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.

What does the gdprApplies value mean?

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).

Details for vendors

How can scripts on a page determine if there is a CMP present?

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).

How can scripts determine if the CMP script is loaded yet?

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.

How does the CMP "stub" API work?

  1. 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).
  2. This "stub" will:
    1. Define a queuing function named __tcfapi at the Window scope.
    2. All arguments for a given call to the stubbed __tcfapi method will be enqueued as a set.
    3. Define the postMessage handler function for cross-origin iframe requests.
    4. Add the newly-created postMessage handler function as an event listener on the Window object listening for the ‘message’ event.
    5. Create an iframe named '__tcfapiLocator' in the current DOM.
  3. When the main CMP implementation script loads and executes, it will:
    1. Create an internal reference to the queued argument sets of the "stub".
    2. Redefine the __tcfapi function to the CMP’s full API implementation.
    3. 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.

Requirements for the CMP "stub" API script

A CMP must provide stub script to its clients that at least supports the following features/logic:

  1. __tcfapi function that supports the ping command, with the minimum properties of cmpLoaded and apiVersion. Note: gdprApplies may also be set in the PingReturn 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, be undefined. See the section "What does the gdprApplies value mean?" for more.
  2. Collect all calls to __tcfapi that cannot (yet) be handled by the “stub” in a queue
  3. Check if window.frames['__tcfapiLocator'] exists, indicating that a CMP is already present, otherwise create an empty iframe named '__tcfapiLocator' in the current DOM.
  4. Create an event listener for postMessage events on the Window object. When the event handler function receives a postMessage (‘message’) event it shall proxy the __tcfapi function requests to send the response back through the postMessage event channel
  5. 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.

Is there a sample CMP “stub” API script?

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.

How can vendors that use iframes call the CMP API from an iframe?

The only way to request TC Data from a parent or ancestor’s frame is using postmessage.

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
  }
}

Is there a sample iframe script call to the CMP API?

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

});

From where will the API retrieve the TC string?

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.

Major Changes from 2.0

  1. Deprecated command getTCData

Major Changes from 1.1

  1. Added getInAppTCData
  2. Added properties to PingReturn
  3. Added addEventListener
  4. Added TCData
  5. Removed VendorConsents
  6. Removed VendorConsentData
  7. Changed getVendorConsents to getTCData
  8. Renamed __cmp to __tcfapi
  9. Renamed all __cmp* to __tcfapi* (e.g. __cmpLocator is now __tcfapiLocator)
  10. Removed getConsentData and getPublisherConsents commands (data moved to getTCData)
  11. Added in-app API details throughout where applicable
  12. Removed SafeFrame proxy communication