Intent to implement.
Status: Open for comment.
This technical specification explains the implementation of TCF 2.0 in Prebid.js. IAB's TCF 2 is coming in April 2020. TCF 1.1 is going to be fully deprecated after April. Prebid will update consent management module to support both the versions.
Prebid js api will remain same for Publishers. Consent management module will first try to use v2 and then fallback to v1 if not found.
pbjs.setConfig({
consentManagement: {
gdpr: {
cmpApi: 'iab',
timeout: 3000,
allowAuctionWithoutConsent: false
}
}
});
Prebid will add new property apiVersion to the gdprConsent object. This will help bidder adapters in parsing the consent string and reading vendor data
gdprConsent: {
consentString: 'BOKAVy4OKAVy4ABAB8AAAAAZ+A==',
consentRequired: true,
vendorData: <vendor data>,
apiVersion: 2
}
As per IAB spec for TCF 2.0, CMPs are required to support four API commands: 'getTCData', 'ping', 'addEventListener' and 'removeEventListener'
// Sample call
__tcfapi('getTCData', 2, (tcData, success) => {
if(success) {
// do something with tcData
} else {
// do something else
}
}, [1,2,3]);
// Sample call
__tcfapi('ping', 2, (pingReturn) => {
// do something with pingReturn
});
| 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. |
// Sample call
const callback = (tcData, success) => {
if(success && tcData.eventStatus === 'tcloaded') {
// do something with tcData.tcString
// remove the ourself to not get called more than once
__tcfapi('removeEventListener', 2, (success) => {
if(success) {
// oh good...
}
}, callback);
} else {
// do something else
}
}
window.__tcfapi('addEventListener', 2, callback);
Below diagram and use cases details the general approach to be followed by consent management module to get tcString.

tcloaded, Prebid will remove the callback using removeEventListener api command, clear the timer and get the tcstring. cmpuishown, Prebid will first check if tcstring is available and if purposeOneTreatment is set to true then it will try to get the tcstring and exit. If eventStatus is useractioncomplete, Prebid will clear the timer and get the tcstring.
In this case prebid will not be able to find window.__tcfapi as CMP is in an iframe or top window.
addEventListener command to cmp iframe found in step 2. {
__tcfapiCall: {
command: "<tcf api command>",
parameter: <arguments>,
version: <version>,
callId: <random id to match postmessage request response>
}
}
{
__tcfapiReturn: {
returnValue: <TCData object>,
success: boolean,
callId: <unique id from the request>
}
}
tcloaded, Prebid will remove the callback using removeEventListener api command, clear the timer and get the tcstring. cmpuishown, Prebid will first check if tcstring is available and if purposeOneTreatment is set to true then it will try to get the tcstring and exit. useractioncomplete, Prebid will clear the timer and get the tcstring.Hey @jaiminpanchal27
Thanks for putting this together. I had a few questions/items I wanted to confirm:
api_version field in the gdpr_consent object, will we want to update the logic to specify 1 for anyone using the v1 CMPs?tcloaded or useractioncomplete events, we do not need to check for the purposeOneTreatment in the string before accepting it?cmpuishown and then later useractioncomplete?Hi @jaiminpanchal27
To add on @jsnellbaker questions
purposeOneTreatement is not set to true or is not present?thanks
@jsnellbaker
getTCData to see if the eventStatus is already tcloaded or useractioncomplete, meaning that the consent data is already in a state that's ready to be used? The concern is that the _TC String_ may not change and therefore never fire an event. don't need to do this because: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.
__tcfapi() in parent windows (in case we're in a "friendly" iframe), since that is more direct than dealing with postMessage() or the SafeFrame interface. cmpApi:
consentManagement: {
gdpr: {
cmpApi: 'static',
consentData: {
getTCData: {
tcString: 'base64url-encoded TC string with segments',
gdprApplies: true
}
}
}
}
for #4 - static API. Wasn't this considered a bad pattern because then any following code/creative dropped would expect to read the consent data but would not find it in the page? IE single source of truth is not there..? @harpere
@mkendall07 - The use case for the static API as I understand it is pubs that cache consent data in first party cookies. If they detect that the user has already answered the CMP, they don't even load the CMP for subsequent pages. Adding @patmmccann for comment.
@harpere - there's a difference here with the way static data is handled for TCF1.1 From http://prebid.org/dev-docs/modules/consentManagement.html
consentManagement: {
gdpr: {
cmpApi: 'static',
allowAuctionWithoutConsent: false,
consentData: {
getConsentData: {
'gdprApplies': true,
'hasGlobalScope': false,
'consentData': 'BOOgjO9OOgjO9APABAENAi-AAAAWd7_______9____7_9uz_Gv_r_ff_3nW0739P1A_r_Oz_rm_-zzV44_lpQQRCEA'
},
getVendorConsents: {
'metadata': 'BOOgjO9OOgjO9APABAENAi-AAAAWd7_______9____7_9uz_Gv_r_ff_3nW0739P1A_r_Oz_rm_-zzV44_lpQQRCEA',
...
}
}
}
}
Is the difference on purpose?
@jaiminpanchal27 - is the proposal that the bidrequest interface is different for TCF2?
Currently adapters read:
It appears this spec defines different locations:
Is this on purpose?
@jaiminpanchal27 can we keep the interface the same as of TCF1? then no changes will be required by bidders otherwise all bidders will need to update their code.
I think it would ideal to implement a version field into the bidderRequest.gdprConsent object. Part of the changes with the spec and with the updates to the module relate to the vendorData object.
In the v1, this value was pulled from the CMP through a dedicated API call named getVendorConsents. In v2, (I imagine) this value would be tcfData object that comes back from the events, as that object contains the breakdown of the various purpose/vendor consent settings.
These two objects that we get from the CMPs are structured differently and (I believe) contain unique fields. Since we have several adapters reading these values from the vendorData object to control parts of their logic, they'll need to know when the object is in v1 or v2 (so they can look at the appropriate fields for that version).
Also - it has been requested that if a _consent string_ changes while a user is on a page, we should use the updated _consent string_. So, should we remove the eventListener after we receive an eventStatus of tcloaded or useractioncomplete, or should we continue to listen and update the _consent string_ if it changes?
@jaiminpanchal27 - is the proposal that the bidrequest interface is different for TCF2?
Currently adapters read:
- bidderRequest.gdprConsent.gdprApplies
- bidderRequest.gdprConsent.consentString
It appears this spec defines different locations:
- bidderRequest.gdpr_consent.consent_required
- bidderRequest.gdpr_consent.consent_string
- bidderRequest.gdpr_consent.api_version
Is this on purpose?
@bretg @pm-harshad-mane That was by mistake. I updated it.
@harpere Thanks Eric for reviewing,
2) Updated both use cases when trying to find window.__tcfapi. We should also look at top window to find tcfapi.
3) Updated the use case to find v1 as backup.
Also updated to not remove listeners as consent string may get updated.
in regard to the "static" question by @bretg - this is consistent. the format is: consentManagement.gdpr.consentData.<command>.<paramname>
with TCF 1.1 we have:
with TCF 2.0 we have:
I don't believe this layer of code needs to check Purpose 1 or PurposeOneTreatment.
My understanding is that the reading the consent string can be done without Purpose 1 consent. Will confirm this.
@jaiminpanchal27 Can you confirm the bidders don't have to update their adaptors to fetch the signals gdprApplies and consentString as they remain the same?
Can you confirm the bidders don't have to update their adaptors to fetch the signals gdprApplies and consentString as they remain the same?
We are waiting until the change is in Master.
@epouradier The gdprApplies and consentString fields for bidder adapters will remain the same with the TCF2 updates, so if you're only reading those fields and don't need to send a different signal to your system (ie to signify its TCF2) - you should likely be fine.
If you're reading the vendorData field, you will likely need to make some updates, as the inner fields/properties will change with TCF2. I did a pass-through in PBJS to see which adapters would likely be impacted and noted them in the PR description (#4911).
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Most helpful comment
@epouradier The
gdprAppliesandconsentStringfields for bidder adapters will remain the same with the TCF2 updates, so if you're only reading those fields and don't need to send a different signal to your system (ie to signify its TCF2) - you should likely be fine.If you're reading the
vendorDatafield, you will likely need to make some updates, as the inner fields/properties will change with TCF2. I did a pass-through in PBJS to see which adapters would likely be impacted and noted them in the PR description (#4911).