There are two options for sharing consent across multiple domains that you or your company owns or manages.
- You can share consent via an iframe by hosting our provided HTML code at a specific URL, which you pass to Quantcast Choice through a configuration option.
Note: This contains updated sample implementation to support TCF v2 and the Google 'addtl_consent' cookie. - Or you can build your own custom Consent API, which requires significant development work and support.
Note: ITP browsers (Safari, Firefox) and any other third-party-cookie-blocking may prevent the fetch to the cookie from working, therefore disallowing the Group Consents Via Iframe to function. However, developers can use our Group Consents Via Custom Consent API guideline to build out support for Safari and Firefox.
This section provides details on the following sharing customizations:
- Group Consents Via Iframe
- Group Consents Via Custom Consent API
- Cookies to be Handled by Group API
- Responding to GET requests
- Sample JSON Response
Other documents in this series:
User Guide
Prepare for Google to join TCF V2
Group Consents Via Iframe
There are 3 steps to sharing consent across domains via an iframe.
- The configuration option "Consent Scope" must be set to "service group".
- The iframe HTML we provide below must be hosted on a URL determined by the site owner domain.
- The URL where the HTML is hosted must be passed to Quantcast Choice via the configuration option under the option "CONSENT SCOPE GROUP URL" in the Choice Portal.
The iframe HTML:
<!--
For publishers whose consent scope is group level,
host this html at the group level cookie access url.
-->
<html>
<head>
<script type="text/javascript">
function getCookie(name) {
var cookies = document.cookie
.split(';')
.filter(function(s) {
var cookie = s.trim();
if (cookie.indexOf(name + '=') === 0) {
return true;
};
})
.map(function(s) {
return s.trim().substring(name.length + 1);
});
return cookies;
}
var msgIsString = true;
function iframeCookieAccessMsgHandler(event) {
var msg = event.data;
msgIsString = typeof msg === "string";
var json;
if (msgIsString) {
json = event.data.indexOf("__qcCmpCookieAccessCall") !== -1 ? JSON.parse(event.data) : {};
} else {
json = event.data;
}
if (json.__qcCmpCookieAccessCall) {
var obj = json.__qcCmpCookieAccessCall;
var cookieNames = ['euconsent-v2', 'addtl_consent'];
var localNames = ['_cmpRepromptHash', 'noniabvendorconsent'];
if (cookieNames.indexOf(obj.cookieName) === -1 && localNames.indexOf(obj.cookieName) === -1) {
return;
}
var returnObj = {
"callId": json.callId,
"__qcCmpCookieAccessReturn": {
"cmd": obj.cmd
}
}
if (obj.cmd === "set") {
if (cookieNames.indexOf(obj.cookieName) !== -1) {
document.cookie =
obj.cookieName +
'=' +
obj.cookieValue +
';path=' +
obj.cookiePath +
';expires=' +
obj.expires +
';domain=' + window.location.hostname +
';SameSite=None;secure'
} else {
localStorage.setItem(obj.cookieName, obj.cookieValue);
}
returnObj.__qcCmpCookieAccessReturn.isSuccess = true;
} else if (obj.cmd === "get") {
var consentCookies = null;
var infoObj = null;
if (cookieNames.indexOf(obj.cookieName) !== -1) {
consentCookies = getCookie(obj.cookieName);
infoObj = returnObj.__qcCmpCookieAccessReturn;
if (consentCookies.length !== 0) {
infoObj.cookies = consentCookies;
infoObj.isSuccess = true;
} else {
infoObj.isSuccess = false;
}
} else {
consentCookies = localStorage.getItem(obj.cookieName);
infoObj = returnObj.__qcCmpCookieAccessReturn;
if (consentCookies) {
infoObj.cookies = consentCookies;
infoObj.isSuccess = true;
} else {
infoObj.isSuccess = false;
}
}
}
event.source.postMessage(msgIsString ?
JSON.stringify(returnObj) : returnObj, "*");
}
}
if (window.addEventListener) {
window.addEventListener('message', iframeCookieAccessMsgHandler, false);
} else {
window.attachEvent('onmessage', iframeCookieAccessMsgHandler);
}
// post a message to CMP that the event handler is loaded.
var registeredMessage = { "__qcCmpCookieAccessReturn": { "isHandlerRegistered": true } };
window.parent.postMessage(msgIsString ? JSON.stringify(registeredMessage) :
registeredMessage, "*");
</script>
</head>
<body></body>
</html>
Group Consents Via Custom Consent API
Configuring the CMP to use group-level consents requires building a JSON API that handles GET and POST requests to retrieve and store the consent values. Additionally the API should properly respond to OPTIONS requests.
The API requires appropriate CORS headers for all GET, POST, and OPTIONS requests from an allowed origin (domains in your group). Make sure the following headers are included on responses, replacing values in [] as needed:
access-control-allow-credentials: true
access-control-allow-headers: true
access-control-allow-methods: get, post
access-control-allow-origin: http[s]://[your group domain]
Cookies to be Handled by Group API
The CMP expects that the JSON API is able to both receive and provide responses for the following cookies:
Cookie Name | Purpose |
euconsent-v2 | TCF Vendor Consent String |
addtl_consent | Google Additional Vendor Consent string (if applicable) |
noniabvendorconsent | Non-IAB vendor list created within Choice (if applicable) |
_cmpRepromptHash | Hash that controls reprompt operations of the CMP |
Responding to GET requests
When the API receives a GET request, it should respond by retrieving the cookie(s) from the HTTP request header. Note that cookie headers may include more than one cookie.
The consent cookie is in the format:
[cookie name]=[cookie value]
Where [cookie value] denotes the specific value provided by the CMP for the cookie.
The API should then send a JSON response in the format:
{ “[cookie1 name]”: "[cookie1 value]",
“[cookie2 name]”: "[cookie2 value]", .... }
Note that the service group scheme requires the API parse and return both euconsent-v2 and addtl_consent cookies.
Responding to POST requests
When the API receives a POST request, it should respond by setting the cookie(s) sent in the JSON request's body.
The API should expect the JSON be in the format:
{ “[cookie1 name]”: "[cookie1 value]",
“[cookie2 name]”: "[cookie2 value]", .... }
Where [cookie value] denotes the encoded string provided by the CMP for the specific cookies.
The API should emit the following HTTP response headers, in order to set the cookie, replacing values in [] as needed:
set-cookie: [cookie name]=[cookie value]; max-age=15552000; domain=.[your group domain]; path=/
Note that the CMP will execute a POST call for each cookie for which it sets a value, and it expects the Group API to provide a cumulative response for all the cookies that have been set, both in the POST request and the GET request.
Sample JSON Response
{
"euconsent-v2": "COytA2wOytA2wAKABBENAjCsAP_AAAAAAChQF5EX2S5OI2tjI2YdF5BEYYwfJxyigMgChgQIsS4NwIeFbBoGL2AAHBG4JCQAGBAEEACBAQIkHGBcCQAAgIgBiRCMQEmMCzNKBJJAggEbM0FACCVmHkHSmZCY7064O__TAvIisyVJwCxoUChBotQIhDCBAOIUQBgCUMAAECVhsBDgjYFAR6gAAgIjAASAAwAEEgAAIABAAAgKgAAAEBACICIRAAAgEaAhABBIEAEiJEgAAAQA0cACSYISDGDiQCj7YAA.YAAAAAAAAAA",
"_cmpRepromptHash": "CO43p9wO43p9wAKALCENA1CsAP_AAH_AAAwIGatd_X9fb2vj-_5999t0eY1f9_63v-wzjgeNs-8NyZ_X_L4Xr2MyvB36pq4KmR4Eu3LBAQFlHOHcTQmQwIkVqTLsbk2Mq7NKJ7LEilMbM2dYGG9Pn8XTuZCY70_sf__z_3-_-___67bgZeQSYal8BAkJYwEk2aVQogQhXEhUA4AKKEYWjSw0JHBTsrgI9QQIAEBqAjAiBBiCjFkEAAAAASURACQDAgEQBEAgABACtAQgAIkAQWAEgYBAAKAaFgBFEEoEhBkcFRyiBAVItFBPNGAA.YAAAAAAAAAAA.1.KTvSi1ifP7BGbdpiCttXPA==",
"addtl_consent": "1~7.4.1.23.4.4.3.9.6.1.4.4.13.6.4.15.9.5.2.7.4.1.7.1.3.2.4.6.3.5.4.13.8.4.6.9.7.3.7.2.9.2.12.6.7.6.14.5.19.1.6.5.1.3.1.11.10.2.17.4.14.4.4.1.3.10.6.2.9.5.1.6.4.5.3.1.4.29.4.5.3.1.6.2.2.17.1.17.10.9.1.8.3.3.2.8.1.2.1.2.1.134.8.4.8.35.7.15.1.14.3.1.8.10.14.11.3.7.25.5.18.9.1.6.17.24.2.4.1.17.21.3.4.2.1.6.6.5.2.14.18.7.3.2.2.8.19.1.8.8.6.3.10.4.1.3.1.7.8.2.4.9.3.1.6.4.10.1.1.3.2.4.12.4.16.8.8.2.4.11.6.5.1.4.5.7.7.8.1.11.8.1.10.28.8.4.1.3.9.12.2.7.2.4.1.9.20.10.14.3.4.9.15.2.6.7.3.6.6.7.2.4.1.7.12.5.5.3.17.5.10.3.2.12.2.2.2.6.1.4.15.2.4.9.4.4.1.1.3.7.1.2.10.5.3.12.4.7.6.4.13.1.8.2.15.2.5.2.3.1.2.2.1.1.1.14.4.3.4.5.3.2.9.7.2.1.12.6.5.7.13.1.1.18.1.1.3.1.1.9.7.2.11.5.4.3.2.1.14.8.3.1.5.3.5.4.8.4.2.2.6.1.9.2.13.4.2.4.2.9.6.3.4.3.1.4.2.3.6.10.11.2.4.3.16.3.8.3.3.1.2.3.2.7.19.9.2.7.5.3.3.8.2.7.6.4.3.3.1.9.3.3.3.1.1.1.6.11.3.1.1.7.4.3.3.1.10.5.2.6.3.2.1.1.3.1.3.2.2.4.3.2.13.7.6.6.2.1.6.4.5.4.3.2.2.4.1.3.1.1.1.5.6.1.6.9.1.4.1.2.1.7.2.8.3.8.1.3.1.1.2.1.3.2.2.4.1.5.6.1.5.3.1.3.1.1.2.2.7.7.1.4.1.2.6.1.2.1.1.3.1.1.4.1.1.2.1.2.6.1.3.4.4.1.2.2.1.3.1.4.3.6.3.3.3.1.12.3.10.28.1.2.1.1.4.2.1.5.2.1.4.1.1.4.1.3.4.3.1.3.1.3.1.1.3.1.2.3.3.1.1.2.2.2.1.1.2.2.2.1.2.1.1.1.2.2.2.2.2.1.2.2.2.4.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.2.2.1.1.2.1.2.1.3.1.3.1.2.1.1.1.2.1.1.1.1.2.1.1.2.1.2.1.1.2.6.1.1.1.3.2.2.1.6.5.1.1.1.1.1.2.1.1.3.1.1.2.2.1.1.2.2.1.1.4.2.1.1.2.3.2.1.2.3.1.1.1.1.4.1.1.1.1.3.1.1.8.1.2.1.1.5.1.1.3.2.1.1.1.2.3.1.1.1.2.2.1.2.2.2.2.1.1.1.1.11.1.3.1.1.2.2.1.1.3.2.1.1.1.2.1.4.1.1.1.1.1.3.2.1.1.2.5.1.9.4.1.1.3.1.4.3.1.2.2.5.1.1.2.1.2.1",
"noniabvendorconsent": "O5HcfyO5HcfyAKAaAALA"
}
Sample Code for Developers
Quantcast has provided sample code here to illustrate an implementation of "Group Consents Via Custom Consent API." Quantcast will not be providing support on this sample code, and is not responsible for any consequences of your implementation of this sample code.