Google suggests the code needs to be the first thing in the head tag, so I'm wondering if modifications to it would interfere with its functionality?
Actually it does not matter where you put the code. The earlier/higher you put it the earlier the browser will load it, execute it and send a pageview.
If you prefer page performance (e.g. web core vitals) over misleading tracking, you can replace the async attribute with a defer attribute which will cause GA to load later (e.g. after your page is "ready").
I prefer deferring GA. For us there is no point in measuring pageviews which bounce even before the page is "ready".
Please take into consideration that if you use both - GA4 and AW - the code would look like
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXX');
gtag('config', 'AW-00');
</script>
You do not include it twice.
There's documentation from Google for Consent Mode and about Privacy
Your code would look like this:
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied'
});
gtag('js', new Date());
gtag('config', 'G-XXX');
gtag('config', 'AW-00');
</script>
And here's a brief walkthrough:
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXX"></script>
This loads the tracking code/library. Once it is loaded, it will override the dataLayer.push
method and process all entries of the dataLayer array (if there are any). If you would only have this line of markup, nothing would happen. No cookies, no tracking.
window.dataLayer = window.dataLayer || [];
This is some precaution. We cannot be sure if the tracking code/library has been loaded and executed (and declared the dataLayer variable), so we check if dataLayer is undefined. If is undefined we initialize it as an empty array.
function gtag(){dataLayer.push(arguments);}
For easier usage and/or branding we wrap the dataLayer.push()
method call in a function called gtag
. You could use cl22 or timw instead, it would not matter.
gtag('consent', ...
If you would inspect dataLayer now, it would look like this:
[
[
"consent",
"default",
{
"ad_storage": "denied",
"analytics_storage": "denied"
}
]
]
If push
method was already overridden by GA4, this would have been already executed. If not it would sit there and wait until GA4 loads.
gtag('js', new Date());
This creates a timestamp.
gtag('config', 'G-XXX');
This will initialize tracking. In default setups, this will send a page_view event. Here GA4 would set its cookies, but because of our previous "entry" it won't.
gtag('config', 'AW-00');
This will initialize AdWords.