Using Google tag manager with Next js takes two simple steps.
There are three ways to place GTM scripts.
This tutorial discusses two ways to place and trigger GTM scripts. To implement GTM without a History Change Trigger (third way), check Google Analytics 4 Next.js Template without History Change Trigger. This method also addresses the Multiple installations of google tag manager detected warning.
Google tag manager is inherently designed with traditional request-response based websites in mind. If you use client-side rendering technologies like React js or Next js to server-side render a client-side application, you may already have noticed that google tag manager will not work out of the box. But Google tag manager has a built-in solution for this.
If you already have created a Google Analytics account, you should have two analytics tracking tags ready. If you haven't already done so, head on to https://tagmanager.google.com and create an account. Upon account creation, you will be presented with two javascript tags.
/*Google Tag Manager - as high in the <head> of the page*/
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager --></head>
/*Google Tag Manager (noscript)*/
<!--immediately after the opening <body> tag-->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
These two tags need to be placed high in the <head> of the page and immediately after the opening <body> tag. </body></head>
There are two ways to implement google tag manager in Next js. However, both methods require a History change trigger in the google tag manager console. Check the article Google Analytics 4 Next.js Template without History Change Trigger on how to do it without a History Change Trigger.
Below we discuss both methods in detail. Ensure to implement only one of these methods to avoid duplicate gtm tags.
Depending on your Next js app architecture, you can place the above scripts somewhere in _app.js, layout.js, or _document.js. Make sure to place it in a resource shared by every page in your application. If you have a _document.js, you can place the script in the <Head/> section of the _document.js. You can use the below script tag to insert scripts inline without creating additional javascript files. Ensure to place the <script> and <noscript> tags in the proper position.
For Nextjs 11 and up, use the next/script tag to insert the script into the page. The <Script> tag provides several advantages such as lazy loading preferences. More information here.
<Script strategy="afterInteractive" dangerouslySetInnerHTML={{ __html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');`}}></Script>
<script dangerouslySetInnerHTML={{ __html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');`}}></script>
Now place the page script at the beginning of the body tag. Ensure this is visible to every page in your application.
<noscript dangerouslySetInnerHTML={{ __html: `<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe>`}}></noscript>
The below example shows the scripts inserted in the _document.js file. You may select the script location based on your Next app architecture.
import Document, { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'
class WebDocument extends Document {
render() {
return (
<Html lang="en-US">
<Head>
<Script strategy="afterInteractive" dangerouslySetInnerHTML={{ __html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');`}}></Script>
</Head>
<body>
<noscript dangerouslySetInnerHTML={{ __html: `<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe>`}}></noscript>
<Main/>
<NextScript />
</body>
</Html>
)
}
}
export default WebDocument
We are not done yet. If you decide to go ahead with this method, jump on to configure the History change trigger.
Using react-gtm-module is the easiest and cleanest way to implement the gtm in Next js. There are two easy steps to this.
First, you will have to include the react-gtm-module in the package.json file. To do that, open a command prompt and navigate to your app root folder, and type
or
edit your package.json file and add
Now pick a shared page (as mentioned in the google page scripts option above) and insert the gtm tracking code.
import { useEffect } from 'react';
import TagManager from 'react-gtm-module';
function MyApp({ Component, pageProps }) {
useEffect(() => {
TagManager.initialize({ gtmId: 'GTM-XXXXX' });
}, []);
return <Component {...pageProps}/>
}
export default MyApp
So far, everything seems to be in place. When you enter your website by typing the URL, you will notice that google analytics tracks the visit. But once you start navigating within your website by clicking react or next <Link> elements, you will not see any subsequent clicks registered. In other words, Google is unable to track page navigations occur within our website. Therefore, Google can track only initial page loads where a full page load occurs.
The reason is React js or Next js does a full page load only when the page is loaded initially. They do not refresh the page in consequent navigations. That's the correct behavior. That's how we experience those seamless and efficient page transitions. Therefore, our google tracking scripts are executed only once, when we initially visit the page.
The easiest solution is to add a history change trigger in the Google tag manager console. We can tackle the code on our application side and implement a solution. But there is a built-in solution for this in the Google tag manager console. The History Change trigger can capture all the navigations perform on the client-side using React or Next router links.
Don't forget to publish your workspace container.
That's all to it.
Now start a debug session by clicking the Preview button on the top right.
Once you click start, the tag manager will open a debug window connected to your website. You can use this window to navigate your website links.
You will notice that there is a History created for every page transition that happens within the website. Every page refresh will result in Container, DOM, and Window events.
Nextjs does a full page load only when the page is loaded initially. It does not refresh the page in consequent navigations. Therefore, the Google Analytics tracking scripts are executed only at the initial page load. To overcome this, we can use Google's History Change trigger. The History Change trigger fires when the URL fragment changes or when the site uses the HTML 5 push state API.