As the title mentions I get the following error on loading the page
window.gtag is not a function
I use Next.js 14.0.4
all solutions I have seen so far basically make data collection impossible, meaning the website I built does not set the cookie consent correctly. At this point I am unsure on how to correctly proceed. As I will show in the code, there are multiple data types I want to collect. So far with only one it worked but now it started to throw errors. I also had more errors since upgrading to next14
I used the packages @types/gtag.js and client-only for this.
my layout.tsx looks as follows:
<html lang='en'>
<head>
<GoogleAnalytics />
</head>
<body className='overflow-x-hidden mx-auto w-[100vw] flex flex-col items-center justify-center box-border'>
<Toaster />
<Navbar />
<div className="right-10 md:right-0 -top-10 md:top-10 absolute w-[100vw] h-[230px] gradient-02 -z-50 hidden sm:block" />
<main className='w-[100vw] overflow-x-hidden mx-auto'>
{children}
</main>
<Footer />
<CookieBanner />
</body>
</html>
and this is my CookieBanner Component:
'use client';
/**
* Type Definition
*/
type ConsentState = {
adStorage: boolean
analyticsStorage: boolean
}
export default function CookieBanner() {
// Define useState
const [cookieConsent, setCookieConsent] = useState<ConsentState>();
// useEffect checks if cookie_consent is already set
useEffect(() => {
const storedCookieConsent = getLocalStorage("cookie_consent", null);
setCookieConsent(storedCookieConsent);
}, [setCookieConsent]);
// useEffect updates once cookieConsent is updated to update the consent values
useEffect(() => {
const adStorage = cookieConsent?.adStorage ? 'granted' : 'denied'
const analyticsStorage = cookieConsent?.analyticsStorage ? 'granted' : 'denied'
// Check if window.gtag is there
if (typeof window !== 'undefined' && typeof window.gtag !== 'undefined') {
window.gtag("consent", 'update', {
'analytics_storage': analyticsStorage,
'ad_storage': adStorage,
});
console.log("Cookies set")
} else {
console.warn("gtag is not defined, cannot update consent.");
}
setLocalStorage("cookie_consent", cookieConsent);
}, [cookieConsent]);
return (
<div
className={`my-10 mx-auto max-w-[90%] md:max-w-screen-sm
fixed bottom-1 left-0 right-0
${cookieConsent != null ? "hidden" : "flex"} px-3 md:px-4 py-3 justify-between items-center flex-col gap-4 text-[17px]
bg-[#2E3A59] rounded-lg shadow-white shadow z-50`}
>
<div className='flex flex-col sm:flex-row items-center justify-between gap-y-3 w-full'>
<div className='text-center sm:text-left text-stone-200 w-fit min-w-[50%]'>
<Link href="/datapolicy" aria-label='Link to Data Policy'><p>This site uses <span className='font-bold text-primary hover:underline duration-1000'>Cookies.</span></p></Link>
</div>
<div className='flex gap-4 items-center justify-center w-full'>
<Button onClick={() => setCookieConsent({ adStorage: false, analyticsStorage: true })} size="md" variant="ghost" className='max-w-[33%] flex flex-col items-center justify-center' aria-label='Accept required Cookies'>
<span>Accept</span>
<span className='text-[11px]'>(required only)</span>
</Button>
<Button onClick={() => setCookieConsent({ adStorage: true, analyticsStorage: true })} size="md" variant="secondary" className='max-w-[60%]' aria-label='Accept all Cookies'>
Accept All
</Button>
</div>
</div>
</div>
)
};
this should run as fas as i am concerned. I tried it with adding GoogleAnalytics at different places in the layout and also changes in the cookie banner. So far nothing which would help. It is just always the same error. At least with the conditionals regarding the if statement for window.gtag the website runs. But this still hinders data collection.
thanks in advance!
I think what is happening is typescript doens't know your window now has gtag, as you probably added it in a script inside _app or something like that I'm guessing.
If it's only used in the CookieBanner component you could add
at the top. Otherwise you'll need to add it to a higher level component.