next.js
                                
                                 next.js copied to clipboard
                                
                                    next.js copied to clipboard
                            
                            
                            
                        with-google-tag-manager: `pageview` event doesn't fire on initial page load
What example does this report relate to?
with-google-tag-manager
What version of Next.js are you using?
10.0.3
What version of Node.js are you using?
10.0.3
What browser are you using?
Chrome
What operating system are you using?
macOS
How are you deploying your application?
next start
Describe the Bug
pageview event doesn't fire on initial page load, only routchange
Expected Behavior
to be able set up a single tag in GTM to use the "pageview" dataLayer event, however the routeChangeComplete only fires on subsequent page views.
To Reproduce
- start with-google-tag-manager up the example
- add console.log("pageview");inside the exported page view function
- note in the console that it only appears on subsequent pageviews
We're going with a slight adaptation from the example, using a hook instead of a regular component. Either way, I think the addition of a call to gtm.pageview on initialPage would be a nice addition to with-google-tag-manager.
export default function useGTM() {
  const router = useRouter();
  React.useEffect(() => {
    const handleRouteChange = (url: string) => {
      // Wrap it in a rAF to ensure the correct data is sent
      // https://github.com/zeit/next.js/issues/6025
      requestAnimationFrame(() => gtm.pageview(url));
    }
    router.events.on('routeChangeComplete', handleRouteChange);
    return () => router.events.off('routeChangeComplete', handleRouteChange);
  }, [router.events]);
}
You could try using this package. Init Google Tag Manger in app.js clientside.
React.useEffect(() => {
         // init GA/GTM
        TagManager.initialize({
	        gtmId: "YOUR-GTM-ID"
        })
}, []); 
I have a sneaky suspicion it's related to this https://github.com/vercel/next.js/issues/11535. We've also been having issues with several Pixel trackers who under-reported conversions and we think it's because of a similar reason. I'm investigating now
@RXminuS, perhaps.
The requestAnimationFrame(() => gtm.pageview(url)); bit in our hook (above) might help #11535, I commented there as well.
But, I don't believe that routeChangeComplete is supposed to fire on the initialPage load though. So the primary need to close this issue is for the with-google-tag-manager example to fire a gtm.pageview(url) on the initial page load.
We had the same problem, and therefore opened a PR with a solution we came up with at work!
https://github.com/vercel/next.js/pull/21824
Let me know if it fixes your issue!
@balazsorban44 really interesting approach using the reportWebVitals function! I like the logic behind it a lot and that would certainly solve the issue. Looking forward to seeing the feedback from the Next.js team you added for review.
Hey @dsbrianwebster I've been using GTM quite a bit at work, we had to solve related issues. What you have said about the gtm.pageView event not firing on page load is correct, the main purpose of gtm.pageView is to deal with window.onLoad not firing when routing between pages, which causes issues with reporting.
You can also use the window.onLoad event to push data into the dataLayer, and I'm pretty sure you can use GTM to send data to analytics using triggers and tags.
Without completely understanding what it is you are aiming for, all I can provide is this quick and dirty example:
// _app.js
import '../styles/globals.css'
import { useEffect } from 'react'
function MyApp({ Component, pageProps }) {
  useEffect(() => {
    window.onload = () => {
      window.dataLayer?.push({ event: 'page view from onload' });
    };
  },[])
  return <Component {...pageProps} />
}
export default MyApp
I hope it helps, if not, feel free to give me more detail, e.g. how is the data being fed to analytics, is that even a factor?
p.s. You can also setup a history event trigger to track all history state changes, without using callbacks via routeChangeComplete, but this also won't deal with window.onLoad.
What I also realised is that when I wanted to push more data via pageProps, using router.events didn't help, I've written more detail here in an article.
Hey @dsbrianwebster I've been using GTM quite a bit at work, we had to solve related issues. What you have said about the
gtm.pageViewevent not firing on page load is correct, the main purpose ofgtm.pageViewis to deal withwindow.onLoadnot firing when routing between pages, which causes issues with reporting.You can also use the
window.onLoadevent to push data into the dataLayer, and I'm pretty sure you can use GTM to send data to analytics using triggers and tags.Without completely understanding what it is you are aiming for, all I can provide is this quick and dirty example:
// _app.js import '../styles/globals.css' import { useEffect } from 'react' function MyApp({ Component, pageProps }) { useEffect(() => { window.onload = () => { window.dataLayer?.push({ event: 'page view from onload' }); }; },[]) return <Component {...pageProps} /> } export default MyAppI hope it helps, if not, feel free to give me more detail, e.g. how is the data being fed to analytics, is that even a factor? p.s. You can also setup a history event trigger to track all history state changes, without using callbacks via
routeChangeComplete, but this also won't deal withwindow.onLoad.What I also realised is that when I wanted to push more data via pageProps, using
router.eventsdidn't help, I've written more detail here in an article.
thanks for this
In my case, react1^8, next^13.
window.load is not firing well on every route changing I use useEffect with router.asPath and It works perfectly.
here's my short example
const router = useRouter();
useEffect(() => {
    const delay = setTimeout(() => {
      window.dataLayer.push({
        event: 'ShowPage',
      });
    }, 0);
    // To avoid fire event twice. react^18, on development mode.
    return () => {
      clearTimeout(delay);
    };
}, [router.asPath]);
Experiencing the same problem. I ended up using the react-gtm-module library to conditionally initialize Google Tag Manager (GTM) based on the current environment and set up a custom event (next_route_change) to track all page views (including the initial page load). Here's what the relevant section of my _app.tsx looks like:
export default function App({ Component, pageProps }: AppProps) {
 const router = useRouter()
 useEffect(() => {
   if (process.env.NODE_ENV !== 'production') return
   TagManager.initialize({ gtmId: process.env.NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID })
   gtmEvent('next_route_change')
 }, [])
 useEffect(() => {
   if (process.env.NODE_ENV !== 'production') return
   const routeChange = () => gtmEvent('next_route_change')
   router.events.on('routeChangeComplete', routeChange)
   return () => {
     router.events.off('routeChangeComplete', routeChange)
   }
 }, [router.events])
 return <Component {...pageProps} />
}
Here's my GTM helper function:
export function gtmEvent(event: string) {
  if (!window.dataLayer) return
  window.dataLayer.push({ event })
}
To make typescript happy, I also had to add a global.d.ts file and declare the following types:
declare global {
  interface Window {
    dataLayer: Record<string, any>[]
  }
}
export {}
@philiplindberg thanks for sharing :)
it was not working for me either when I was using the method of the doc example, now it's working using the react-gtm-module, I hate to use libs but this time was all the fault of the Vercel :rage4: