Sharing Consent Between Multiple Sites

Applying the </>GET TAG to Subdomains

When you select Apply to all my subdomains, ensure the following:

  • Use the </> GET TAG instead of the Universal Tag. To find the tag, navigate to Properties, select options and see the </> GET TAG.
  • Implement the </> GET TAG on all sites, not solely on the main site. While Apply to all subdomains aims to streamline efforts by avoiding the creation of multiple properties on our UI portal, it's imperative to implement the tag on each sub-domain site individually.
  • Each site should maintain separate consent. If you need to share consent across multiple domains owned or managed by you or your company, see Sharing Consent Across Multiple Domains.

Sharing Consent Across Multiple Domains

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 InMobi CMP through a configuration option.

    Note

    This contains updated sample implementation to support TCF v2 and the Google addtl_consent cookie.

  • You can also 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 guidelines below to build out support for Safari and Firefox.

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 InMobi CMP via the configuration option under the option "CONSENT SCOPE GROUP URL" in the CMP 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', 'gbc_consent'];

        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
gbc_consent Google basic consents

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

The service group scheme requires the API to parse and return both euconsent-v2 and addtl_consentcookies.

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

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",
  
  "gbc_consent": "[{\"id\":1,\"defaultValue\":\"GRANTED\",\"selected\":true},{\"id\":2,\"defaultValue\":\"GRANTED\",\"selected\":true},{\"id\":3,\"defaultValue\":\"DENIED\",\"selected\":true}]"

}

Sample Code for Developers

InMobi has provided a sample code here to illustrate an implementation of Group Consents Via Custom Consent API. InMobi will not provide support for this sample code and is not responsible for any consequences of your implementation of it.

Displaying IDFA Popup

The CMP provides an option to seamlessly integrate the new native IDFA permission popup (ATTrackingManager), provided the user has been granted permission for the CMP purposes. Presenting the popup right after the CMP offers users more context about the request, potentially leading to higher acceptance rates.

The popup will be triggered if GDPR applies and consent has been obtained or if GDPR explicitly states not to apply.

If your app and associated vendors will never utilize the IDFA, or if you intend to display this popup at a different time, set this option to false.

However, if you set this option to true, provide a usage description in your Info.plist. To do this, add a new key named NSUserTrackingUsageDescription and furnish it with a concise yet comprehensive description of how the IDFA will be utilized. For instance, "We use this value to help serve you relevant advertising".

On This Page

Last Updated on: 06 Apr, 2024