Reputation: 1873
In my Next.js app, I'm setting the <title>
tag for individual pages using the recommended method:
import Head from 'next/head'
export default () => <>
<Head><title>My page title</title></Head>
</>
Here's the problem: when the history change event fires, the value of document.title
doesn't always match the current URL.
You can test it yourself:
Router.events.on("routeChangeComplete", () => {
if ('browser' in process) {
console.log('--------');
console.log(window.location.href);
console.log(document.title);
}
});
Navigating between pages, you should observe that URL & title are often mismatched. The value of URL is always right, but the value of title is all over the place. It can have:
This is an issue when using analytics, specifically GTM - Google Tag Manager, which uses the current URL & page title to uniquely identify visited pages.
I've had this issue with Next.js 7, and upgrading to 8 hasn't fixed it.
Do you know of any way to solve this problem? Maybe delaying the history change event until the first render of a component under /pages/
?
Thanks!
Upvotes: 0
Views: 3222
Reputation: 685
You can use setInterval
const firstPageViewEvent = setInterval(() => {
if (document.title) {
// send pageview event
clearInterval(firstPageViewEvent);
}
}, 200);
Upvotes: -1
Reputation: 1873
I found a work-around by intercepting events sent to window.dataLayer.push
and adding a one-second delay in case the event is gtm.historyChange
.
Here's my GtagScript
component that I'm adding to <Head>
under _document.js
:
export const GtagScript = () => {
function intercept() {
const scriptTag = document.querySelector('#gtm-js');
if (scriptTag !== null)
scriptTag.addEventListener('load', () => {
window.dataLayer.pushOrig = window.dataLayer.push;
window.dataLayer.push = (e) => {
if (e.event === 'gtm.historyChange') {
setTimeout(function () {
window.dataLayer.pushOrig(e);
console.log(`URL: ${window.location.href} Title: ${document.title}`);
}, 1000);
} else {
window.dataLayer.pushOrig(e);
}
};
});
}
return <>
<script
id="gtm-js"
async
src={`https://www.googletagmanager.com/gtm.js?id=${GA_TRACKING_ID}`}
/>
<script
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}');
${intercept.toString()}
intercept();`
}}
/>
</>
};
I'll wait a while to see if an official fix comes from the ZEIT team. My solution doesn't actually answer the question. It doesn't set <title>
, it just defers the event, which isn't optimal.
Upvotes: 1
Reputation: 4810
This is a small hack. setTimeout(()=>{console.log(document.title)}, 0)
Upvotes: 1