DEV Community

Stefan Wright
Stefan Wright

Posted on

Cookie Consent Headaches Across Subdomains

Recently, I ran into a frustrating issue with cookie consent banners popping up on subdomains (moving from subdomain1.example.com to subdomain2.example.com for example). The problem? Our cookie policy covered the entire top-level domain (TLD), so the second banner after consent was already given was redundant.

We were using a Cookie Management Platform (CMP), and this behavior only happened on a few browsers (Safari, Firefox, Brave, you know the ones). We had tried a few workarounds, but they messed up our cookie usage.

For those unfamiliar, these "privacy-focused" browsers block cookies across domains and subdomains to prevent cross-site tracking. While I support privacy, I believe sharing cookie consent between subdomains shouldn't be treated as tracking.

I dug through tons of CMP documentation, but nobody seemed to have a solution. It was either accept the second banner or ditch subdomains (not ideal for an established site).
Then it hit me: iframes! They may be old-school, but they're still useful.

By embedding an iframe from subdomain1.example.com, I could read the consent values and use postMessage to send them to the parent window (subdomain2.example.com). Then, using the CMP's JS API, I updated the consent on subdomain2.

For example, the iframe code that goes in the codebase/hosting on subdomain1 is a basic HTML boilerplate, it loads the CMP javascript, and the inside the body has the following code:

<script>
  function CMPCallback_OnLoad() {
    window.parent.postMessage(
      {
        source: "domainCrossover",
    message: {
      prefs: CMP.consent.preferences,
      stats: CMP.consent.statistics,
      marketing: CMP.consent.marketing,
    },
      },
      "*",
    );
  }
</script>
Enter fullscreen mode Exit fullscreen mode

Then on subdomain2 you would load the iframe hosted from subdomain1 for example, this is how I implemented it (we're using React hence the env variable usage):

<script type="text/javascript">
  const iframeTLD = "%REACT_APP_MAIN_SITE_URL%";
  window.dataLayer = window.dataLayer || [];

  var crossoverProcessMessageEvent = function (event) {
    if (event.data.source === "domainCrossover") {
      window.subdomain1ConsentPreferences = event.data.message.prefs;
      window.subdomain1ConsentStatistics = event.data.message.stats;
      window.subdomain1ConsentMarketing = event.data.message.marketing;
      window.dataLayer.push({ event: "domainCrossover" });
    }
  };
  window.addEventListener("message", crossoverProcessMessageEvent);

  var crossoverIframeNode = document.createElement("iframe");
  crossoverIframeNode.src = iframeTLD + "crossdomain/domaincrossover.html";
  crossoverIframeNode.id = "crossoverExternalIframe";
  crossoverIframeNode.style = "float: left !important; opacity: 0.0 !important; width: 0px !important; height: 0px !important;";

 document.head.appendChild(crossoverIframeNode);
</script>
Enter fullscreen mode Exit fullscreen mode

From a GTM Tag I then read the window variables, and call the CMP JS API to update the consent policy. Then with some GTM configuration changes to trigger tags on the "Consent Updated" event (which comes from the CMP tag on GTM), we had tracking and consent from subdomain1.example.com – all without annoying users with a second banner!

Hopefully, this helps if you're facing a similar issue and want to keep cookie consent consistent across subdomains on those "private" browsers.

Top comments (0)