Delaying Google Analytics until user consent

If your site has visitors from the European Economic Area (EEA), the United Kingdom (UK), or Switzerland, privacy laws require that non-essential tracking tools (including Google Analytics) do not activate until a visitor gives consent.

Google Analytics (GA) uses cookies to track user behavior and collect data such as pageviews, session duration, location, device type, and traffic sources. 

Because this tracking is not strictly necessary for your site to function, it requires opt-in consent in regulated regions.

What does delaying Google Analytics mean?

Delaying Google Analytics means preventing it from activating until a visitor has provided consent, as required by privacy regulations in certain regions.

The GA delay script ensures your site meets these requirements by:

  • Setting Google Analytics consent to “denied” by default in regulated regions
  • Preventing analytics cookies from being stored before consent
  • Turning analytics tracking on only after consent is granted
  • Working alongside Google Consent Mode to respect user preferences

Who this applies to

The delay only applies to visitors located in:

  • European Economic Area (EEA)
  • United Kingdom (UK)
  • Switzerland

Visitors outside these regions will not experience any delay in analytics tracking.

How to add the Google Analytics delay script to your site

Follow the steps below to correctly install the delay script on your site.

Step 1: Identify how Google Analytics is installed

The script you use depends on how Google Analytics (GA) is currently added to your site.

Check which of the following applies:

  • Hardcoded in your theme: you see a GA ID like G-XXXX directly in your theme header file
  • Google Tag Manager (GTM): you see a container ID like GTM-XXXX on your site
  • WordPress plugin
    • MonsterInsights
    • ExactMetrics
    • Site Kit by Google
    • any other analytics plugin

If you're unsure, check

  • Your theme's header file
  • Installed WordPress plugins
  • Your site's source code for G- or GTM- IDs

Step 2: Confirm GA only loads once

Before adding the delay script:

  • Make sure GA is not installed in multiple places (theme + plugin + GTM)
  • Duplicate GA installations are one of the most common causes of tracking issues
  • If multiple versions exist, remove duplicates before proceeding

Step 3: Place the delay script correctly

The delay script must load before your Google Analytics tag. If GA loads first, cookies may be set before consent is granted.

In most cases, this means placing the delay script in the <head> section of your site, above your current GA or GTM code.

Where to place it based on your setup:

  • Hardcoded GA in your theme -> place the delay script above the GA code in your site’s <head>.
  • Google Tag Manager (GTM) -> place the delay script above the GTM container snippet.
  • WordPress analytics plugin -> add the delay script using a header or “custom code” area, ensuring that it loads before the plugin’s analytics code.

If the delay script loads after GA, it will not work correctly

Which script should I use?

Select the script that matches your setup

Each script is tailored to how those tools initialize Google Analytics.

Frequently asked questions:

Standard GA Delay Script

Add this before your Google Analytics tag on your site

<script>
function isUserInEurope() {
  if (
    typeof Intl === "undefined" ||
    typeof Intl.DateTimeFormat === "undefined" ||
    typeof window.__tcfapi !== "undefined"
  ) {
    return true;
  }
  return Intl.DateTimeFormat().resolvedOptions().timeZone.includes("Europe");
}
if (isUserInEurope()) {
  window.dataLayer = window.dataLayer || [];
  function gtag() {
    dataLayer.push(arguments);
  }
  gtag("consent", "default", {
    ad_storage: "denied",
    analytics_storage: "denied",
    ad_user_data: "denied",
    ad_personalization: "denied",
    wait_for_update: 15000,
  });
  dataLayer.push({
    event: "default_consent",
  });
}
</script>

MonsterInsights Script

<script>
(function () {
  function isEU() {
    try {
      if (
        typeof Intl === "undefined" ||
        typeof Intl.DateTimeFormat === "undefined" ||
        typeof __tcfapi === "function"
      )
        return true;
      return Intl.DateTimeFormat()
        .resolvedOptions()
        .timeZone.includes("Europe");
    } catch (e) {
      return true;
    }
  }

  if (!isEU()) return;

  window.dataLayer = window.dataLayer || [];
  const gaIds = new Set();

  window.gtag = function () {
    if (arguments[0] === "config" && typeof arguments[1] === "string") {
      gaIds.add(arguments[1]);
    }
    dataLayer.push(arguments);
  };

  gtag("consent", "default", {
    ad_storage: "denied",
    analytics_storage: "denied",
    ad_user_data: "denied",
    ad_personalization: "denied",
    wait_for_update: 15000,
  });

  dataLayer.push({ event: "default_consent" });

  let enabled = false;

  function enableCookies() {
    if (enabled) return;
    enabled = true;

    gtag("consent", "update", {
      ad_storage: "granted",
      analytics_storage: "granted",
      ad_user_data: "granted",
      ad_personalization: "granted",
    });

    dataLayer.push({ event: "consent_granted" });

    const ids = Array.from(gaIds);
    gtag("js", new Date());
    ids.forEach((id) => {
      gtag("config", id, {
        client_storage: "cookie",
        cookie_domain: location.hostname,
        cookie_flags: "SameSite=Lax; Secure",
        cookie_update: true,
        anonymize_ip: true,
        forceSSL: true,
      });
    });
  }

  (function waitForTCF() {
    const hasConsent = (tc) =>
      !!tc?.purpose?.consents?.["1"] &&
      (!!tc?.vendor?.consents ? !!tc.vendor.consents["755"] : true);

    const init = () => {
      try {
        __tcfapi("getTCData", 2, (tc, ok) => {
          if (ok && tc && hasConsent(tc)) enableCookies();
        });
      } catch (e) {}

      try {
        __tcfapi("addEventListener", 2, (tc, ok) => {
          if (!ok || !tc) return;
          const s = tc.eventStatus;
          if (
            (s === "tcloaded" || s === "useractioncomplete") &&
            hasConsent(tc)
          ) {
            enableCookies();
          }
        });
      } catch (e) {}
    };

    if (typeof __tcfapi === "function") init();
    else setTimeout(waitForTCF, 200);
  })();

  window.__grantConsentForGA__ = enableCookies;
})();
</script>

ExactMetrics Script

<script>
(function () {
  function isUserInEurope() {
    try {
      if (
        typeof Intl === "undefined" ||
        typeof Intl.DateTimeFormat === "undefined" ||
        typeof window.__tcfapi !== "undefined"
      )
        return true;

      var tz = Intl.DateTimeFormat().resolvedOptions().timeZone || "";
      return tz.indexOf("Europe") !== -1;
    } catch (e) {
      return true;
    }
  }

  if (!isUserInEurope()) return;

  window.dataLayer = window.dataLayer || [];
  function gtag() {
    dataLayer.push(arguments);
  }

  gtag("consent", "default", {
    ad_storage: "denied",
    analytics_storage: "denied",
    ad_user_data: "denied",
    ad_personalization: "denied",
    wait_for_update: 15000,
  });

  gtag("set", "url_passthrough", true);
  dataLayer.push({ event: "default_consent" });

  function onTCFReady(cb) {
    if (typeof window.__tcfapi === "function") return cb();
    var tries = 0;
    var t = setInterval(function () {
      tries++;
      if (typeof window.__tcfapi === "function" || tries > 60) {
        clearInterval(t);
        if (typeof window.__tcfapi === "function") cb();
      }
    }, 250);
  }

  function hasMeasurementConsent(tcData) {
    try {
      var consents = tcData?.purpose?.consents;
      return !!(consents && consents["1"] && consents["7"]);
    } catch (e) {
      return false;
    }
  }

  onTCFReady(function () {
    try {
      window.__tcfapi("addEventListener", 2, function (tcData, ok) {
        if (!ok || !tcData) return;
        var status = tcData.eventStatus;
        if (status !== "tcloaded" && status !== "useractioncomplete") return;

        if (hasMeasurementConsent(tcData)) {
          gtag("consent", "update", { analytics_storage: "granted" });
        } else {
          gtag("consent", "update", { analytics_storage: "denied" });
        }
      });
    } catch (e) {}
  });
})();
</script>

Site Kit Script

<script>
(function () {
  function isUserInEurope() {
    if (
      typeof Intl === "undefined" ||
      typeof Intl.DateTimeFormat === "undefined" ||
      typeof window.__tcfapi !== "undefined"
    ) {
      return true;
    }
    try {
      return Intl.DateTimeFormat()
        .resolvedOptions()
        .timeZone.includes("Europe");
    } catch (e) {
      return false;
    }
  }

  window.dataLayer = window.dataLayer || [];
  window.gtag =
    window.gtag ||
    function () {
      dataLayer.push(arguments);
    };

  var inEU = isUserInEurope();

  if (inEU) {
    gtag("consent", "default", {
      ad_storage: "denied",
      analytics_storage: "denied",
      ad_user_data: "denied",
      ad_personalization: "denied",
      wait_for_update: 15000,
    });

    gtag("set", "allow_google_signals", false);
    gtag("set", "allow_ad_personalization_signals", false);
    gtag("set", "ads_data_redaction", true);

    dataLayer.push({ event: "default_consent" });

    if (typeof window.__tcfapi === "function") {
      try {
        window.__tcfapi("addEventListener", 2, function (tcData, success) {
          if (!success || !tcData) return;
          var p = (tcData.purpose && tcData.purpose.consents) || {};
          var granted = !!p["1"];
          if (
            tcData.eventStatus === "useractioncomplete" ||
            tcData.eventStatus === "tcloaded"
          ) {
            gtag("consent", "update", {
              analytics_storage: granted ? "granted" : "denied",
              ad_storage: granted ? "granted" : "denied",
              ad_user_data: granted ? "granted" : "denied",
              ad_personalization: granted ? "granted" : "denied",
            });
          }
        });
      } catch (e) {}
    }
  }

  document.addEventListener("DOMContentLoaded", function () {
    var siteKitTag = document.getElementById("google_gtagjs-js");
    if (!siteKitTag) {
      console.log(
        "Site Kit gtag loader not found — ensure this snippet is placed before Site Kit.",
      );
    }
  });
})();
</script>

Frequently asked questions:

Will delaying Google Analytics affect my traffic reporting?

Yes — you may see lower reported traffic in Google Analytics.

When GA is delayed until consent is granted:

  • Visitors in regulated regions who decline consent will not be tracked.
  • No pageviews or sessions will be recorded for those users.
  • This only affects traffic from the EEA, UK, and Switzerland.

This is expected behavior and reflects privacy-compliant tracking. Your actual traffic has not decreased, only the number of users who have agreed to analytics tracking.

Doesn’t Google Consent Mode already handle this?

Consent Mode adjusts how Google tags behave based on user consent signals, but it does not always prevent Google Analytics from loading before consent.

In some EU countries, regulators expect that:

  • Google Analytics does not initialize at all before consent is granted.
  • No analytics cookies are set before consent.

While Raptive’s CMP already has Google Consent Mode enabled, the GA delay script adds this extra layer of protection by preventing GA from activating until consent is approved.

How can I test that the delay is working?

You can verify the setup using these steps:

  1. Open your site in an incognito/private browser window.
  2. If possible, use a VPN set to an EU country.
  3. Open Chrome DevTools → Application → Cookies.
  4. Refresh the page without clicking “Accept.”
  5. Confirm that no _ga or _gid cookies are present.
  6. Click “Accept” in the consent banner and confirm the cookies then appear.

You can also use:

  • Google Tag Assistant
  • The Network tab in DevTools to confirm GA is not firing before consent
     
Was this article helpful?
0 out of 0 found this helpful
Have more questions? Send a message

Want to join Raptive? Apply here!