Block Google Analytics 4 until visitors accept tracking cookies
Tag both Google Analytics 4 script tags with the tracking category, and by default TermsFeed Free Cookie Consent holds Google Analytics 4 until the visitor accepts tracking. Before the answer, by default, no request reaches Google and no _ga cookie is stored. The moment the visitor accepts, Cookie Consent runs both scripts on the same page, with no reload, and Google Analytics 4 records the page view.
Google Analytics 4 sets cookies that identify a returning visitor. The ePrivacy Directive in the EU and PECR in the UK require consent before these cookies are stored. An untagged Google tag with denied defaults does not store cookies until consent, but its cookieless pings still send data from the device. EDPB Guidelines 2/2023 bring such sending within Article 5(3) of the ePrivacy Directive. With the tagged Google tag, Google receives nothing before consent or from a visitor who declines.
Before you start, put the Cookie Consent code from the TermsFeed generator on your pages and note your Google Analytics 4 measurement ID, which starts with G-. You need access to your site templates, or to the code slot your platform offers.
Tag both Google Analytics 4 script tags with tracking
The Google tag Google gives you is 2 <script> elements, and both need type="text/plain" and data-cookie-consent="tracking". The first element loads the gtag.js library from www.googletagmanager.com. The second element defines gtag() and sends the configuration. An untagged gtag.js loads from Google before consent, so tag both.
Replace G-XXXXXXXXXX in this tagged Google tag with your measurement ID, in both places.
<!-- Google tag (gtag.js), held by Cookie Consent, by default, until the visitor accepts tracking -->
<script type="text/plain" data-cookie-consent="tracking" async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script type="text/plain" data-cookie-consent="tracking">
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>
Keep the async attribute on the external script. Cookie Consent keeps every attribute of a tagged script except type, data-cookie-consent, nonce, and data-nonce when it runs it. An external script without async holds the tracking scripts after it until it loads, fails, or 10 seconds pass. The inline script runs at once and queues its commands in dataLayer, which gtag.js reads when it arrives.
Place the tagged Google tag in <head>, where Google asks for it, or anywhere else in the page markup. Cookie Consent reads tagged scripts once, when run() starts. The generator code delays that until the browser has read the whole page, so the tagged code works from any place in the markup. A tagged script your code adds later never runs. Learn how tagging works for every script in Block Scripts Until Consent.
Load Google Analytics 4 with advanced consent mode instead of the tagged Google tag
The tagged Google tag is what Google calls basic consent mode. In advanced consent mode, the Google tag loads untagged with a denied default, and a callback grants analytics_storage after consent. Google then receives cookieless pings from visitors who decline, which it uses for modeled data once the property meets the behavioral modeling thresholds, and does not store cookies for them. The denied default is the first script in <head>, after only the charset meta, above the Google tag, any Google Tag Manager container, and the Cookie Consent code. Choose advanced consent mode for that modeled data on a property above those thresholds, and the tagged Google tag when you want no request to reach Google before consent.
A tagged Google tag beside a denied default needs the user_consent_saved update as well, or it stays denied after the answer. Set up the untagged Google tag, the denied default, and the callback with Set Up Google Consent Mode v2.
How to verify that Google Analytics 4 waits for consent
The checks assume express consent with page_load_consent_levels left out or at the generator value ["strictly-necessary"], and the "I decline" button shown. Publish the change and clear any page cache before the check. The Network tab shows whether the tagged Google tag waits for the answer, as it does by default. Close every private window, then run the check in a new one, which does not hold a saved answer from an earlier visit.
- Open your site in that window of Chrome, open DevTools, and select the Network tab.
- Type
google-analytics.comin the filter box and reload the page. No request appears while the consent banner shows. - Change the filter to
googletagmanager.com. No request forgtag/jsappears either. - Click the "I agree" button on the consent banner. A
gtag/jsrequest appears. Change the filter tocollect, and acollect?v=2request togoogle-analytics.comwithen=page_viewis listed. - Select the Application tab, open Cookies, and select your site. The
_gacookie and the_ga_cookie that ends in your measurement ID withoutG-are now listed, besidecookie_consent_level. - Close every private window and open a new one. Open DevTools, type
google-analytics.comin the Network filter, load the site, and click the "I decline" button. The filter stays empty, and no_gacookie appears in the Application tab.
With the tagged Google tag, a google-analytics.com request before the answer comes from an untagged copy in your markup, a plugin, a platform setting, or a tag manager. Find the copy that sends it with Scripts Run Before Consent.
Under Consent Mode, the untagged Google tag sends collect requests marked gcs=G100 before the answer, so a check for no request does not apply. Check the cookies instead: the Application tab does not list a _ga cookie before the answer, and lists it after a click on the "I agree" button. Run the full Consent Mode check with Set Up Google Consent Mode v2.
Cookies Google Analytics 4 sets
Google Analytics 4 stores 2 first-party cookies, both with a default lifetime of 2 years, according to the Google Analytics help center. List them in your Cookies Policy under tracking cookies.
| Cookie | Lifetime | Purpose |
|---|---|---|
_ga |
2 years | Distinguishes users |
_ga_<container-id>, where the container ID is your measurement ID without G- |
2 years | Keeps the session state |
A site that runs Google Ads conversion tracking stores Google Ads cookies beside the Google Analytics 4 cookies. Add the Google Ads cookies with Google Ads Conversion Tracking.
Common mistakes with Google Analytics 4
With the tagged Google tag, a request to Google before the answer usually comes from a second, untagged copy. A missing request after a click on the "I agree" button points to the attributes on your own tagged copy, such as a misspelled category. Look for each mistake on every page that carries the Google tag.
- A plugin, an app, or a platform setting adds its own Google tag. Requests to
google-analytics.comappear before you answer. Site Kit for WordPress and the Google Analytics fields of Squarespace and Webflow add an untagged Google tag. Search the page source for yourG-measurement ID to find each copy, remove the measurement ID from that plugin or setting, and keep only your tagged copy. On Shopify, open Settings > Customer events too and remove any custom pixel that loads yourG-measurement ID, because pixels there run outside the page source. Disconnect Google Analytics in the Google & YouTube app. Wix runs Google Analytics only from Marketing Integrations, so Cookie Consent does not hold it on Wix. - A tag manager loads a second copy of Google Analytics 4. A Google tag fired from a tag manager container runs outside Cookie Consent, whatever attributes your own copy carries. Open the container and look for a Google tag with your measurement ID. Remove Google Analytics 4 from the container and keep only your tagged copy.
- Only the inline script is tagged. A
gtag/jsrequest towww.googletagmanager.comappears before you answer. Search the page source for thegtag/jsscript, and check that it carriestype="text/plain". Tag both elements. - The category is misspelled or capitalized.
data-cookie-consent="Tracking"or"analytics"never runs, because the 4 category IDs are case-sensitive and Cookie Consent has noanalyticscategory. Nogtag/jsrequest appears after you click the "I agree" button. Write the category astracking, in lowercase. - A denied default sits beside the tagged Google tag with no update. The Application tab has no
_gacookie after you click the "I agree" button, because a denied default keeps the released tag from storing cookies when no callback sends an update. Search the page source for agtag('consent', 'default'call beside the tagged Google tag. Remove the default, or add theuser_consent_savedcallback from Set Up Google Consent Mode v2. - You expect a withdrawal to remove
_ga. A withdrawal keeps the tagged Google tag from running from the next page load on, but Cookie Consent does not delete cookies set by Google before. The_gacookie stays in the Application tab after the withdrawal. Delete the_gacookies from a callback with the pattern in Rejecting Does Not Delete Cookies Already Set. - You expect sessions to match the numbers from before the consent banner. Google Analytics 4 counts fewer sessions, because visitors who decline send nothing. A
collect?v=2request that appears only after a click on the "I agree" button shows that the tagging works. Load the Google tag untagged in advanced consent mode for modeled data from visitors who decline, which Google produces only once the property meets its modeling thresholds. Set it up with Set Up Google Consent Mode v2.
Google Analytics 4 has no <noscript> fallback, so the Google tag carries nothing to remove for visitors without JavaScript.