When utilizing Google Analytics in conjunction with Next.Js, encountering the error message "window.gtag is not

Encountering an error on page load with the message:

window.gtag is not a function

Using Next.js version 14.0.4.

All existing solutions seem to hinder data collection, preventing the website from setting cookie consent correctly. I am uncertain about the next steps to take. The code shows that multiple data types need to be collected. Initially, it worked with just one type but after upgrading to Next.js 14, errors started to occur. The packages used were @types/gtag.js and client-only.

The layout.tsx file appears 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>

This is the 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>
    )
};

I have tried various approaches like moving GoogleAnalytics to different locations in the layout and making changes to the cookie banner with no success. Despite conditionally checking for window.gtag, the error persists, hindering data collection.

Thank you in advance!

Answer №1

It seems like the issue is that typescript doesn't recognize gtag in your window object, possibly because it was added in a script within _app or another component.

If gtag is only used in the CookieBanner component, you can include the following code snippet at the top:

declare global {
  interface Window {
    gtag: any;
  }
}

Otherwise, you will need to add it to a higher level component for typescript to be aware of it.

Answer №2

To overcome this issue, you can establish the 'gtag' function as a global declaration in your Next.js project. One effective method is to generate declaration files for global variables using the following steps:

  1. Create a new Typescript declaration file within your project's root directory.

custom.d.ts

interface Window {
   gtag: (...args: any[]) => void;
}
  1. Modify tsconfig.json to include the pathway to the folder containing your declaration files, ensuring that the typescript compiler can acknowledge them.

    {
       "compiler options": {
          "include": ["next-env.d.ts", "custom.d.ts"]
       }
    }
    
  2. Implementation in your code:

    // insert your code here
    
    declare global {
       interface Window {
           gtag: (...args: any[]) => void;
       }
    }
    
    // insert your code here
    

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to retrieve nested reference data all at once from a Firestore document?

I have two distinct collections stored within my Firestore database. The first collection is users, and it can be visualized as shown here: https://i.stack.imgur.com/AKlyM.png The second collection is posts, represented by the following structure: http ...

How can I pass an Objective-C object to JavaScript?

Currently, I am working on a UIWebView project that involves HTML and JavaScript. One of my friends is working on something similar but for Android. The challenge I'm facing is that in Android, there is a simple way to send an Android object to JavaS ...

What is the best way to implement a multi-row form in Vue.js?

Form Structure: <card-wrapper v-for="(passenger, index) in form.passenger" :key="index" :icon="['fas', 'user']" :title="`Passenger ${index + 1}`" class="mb-5" > <validation-observer ...

What could be causing my issue with the if-else condition not functioning properly?

Why does the code only work for adding and removing styles in Part (else), but not returning the class when clicked again? var navDropDown = document.querySelectorAll('.menu-item-has-children > a'); for (let i = 0; i < navDropDown.length; i ...

Error: JSON parsing failed due to an unexpected character, resulting in null data

Many people have asked similar questions on the same topic, but I have not been able to find a solution for my specific problem. Below is the code snippet that I am working with: $.post("show_search_results.php", {location_name: ""+location_name+"", key: ...

Using Google Maps to trace a line showing the distance traveled

I want to create a 'distance traveled' polyline along a set route using V3 of the Google Maps API. The polyline should pass through multiple waypoints/legs. Currently, I am using the DirectionsService to draw the entire route. In addition, I a ...

What steps should I follow to bring in an animated SVG file into Next.js 13 without losing transparency and animation effects?

How to Include an Animated SVG File in Next.js 13 import Image from "next/image"; export default function Home() { return ( <main className="flex h-screen flex-col items-center"> <div className="container mt-1 ...

Modify the hover color of <TextField /> within the createMuiTheme() function

Is there a way to change the borderColor on hover for the outlined <TextField /> Component within the createMuiTheme()? I have managed to do it easily for the underlined <Input /> export default createMuiTheme({ MuiInput: { &apo ...

The received reply does not align with the set parameter configuration:

Encountering an issue with Angular $resource: error description Error: error:badcfg Response does not match configured parameter: Error in resource configuration for action `array`. Expected response to contain an object but got an {2} Initialization of ...

Set up a unique database in memory for every individual test

Is it feasible to create an in-memory database for each test scenario? My current approach involves using the code snippet below, which functions properly when running one test file or utilizing the --run-in-band option. import _useDb from "@/useDb&q ...

Personalized HTML selection list

When a select option is too long, it stretches the container to accommodate its length. I have created a truncate function to limit the display to 20 characters and add ellipses to prevent this stretching. I have been searching for a way to show the entir ...

Combining two elements in Angular 2

I am looking to find the intersection of two objects. My goal is to compare these objects and if they have matching values on corresponding keys, then I want to add them to a new object. obj1 = { "Projects": [ "test" ], "Companies": [ "facebook", "google ...

Encountering the error message "Received interpolation ({{}}) when an expression was expected" is a common issue when trying to interpolate tag attribute values within an ngFor loop

I've been working with a Devextreme's Datatable and my goal is to dynamically configure the table using a columns configuration array. The plan is to loop through this array using an ngFor and set column tags properties dynamically. Now, the bi ...

Tips for obtaining cookies within Nextjs api routes

I'm currently working on developing a note-taking application using Next.Js and MongoDB. The login system I have set up allows users to register for an account and login to start creating notes. To handle authentication, JWT is being utilized. Once a ...

What steps should I take to address the issue of sanitizing a potentially harmful URL value that contains a

I've encountered a URL sanitization error in Angular and despite researching various solutions, I have been unable to implement any of them successfully in my specific case. Hence, I am reaching out for assistance. Below is the function causing the i ...

Error encountered: The Bootstrap Carousel function is causing a TypeError as e[g] is not defined

I am attempting to build a dynamic bootstrap carousel using my json data, and I have implemented jQuery-Template for rendering. Essentially, I am generating the carousel slider on-the-fly from my json data with the help of jQuery-Template. Here is a snippe ...

Issue with cookies modification in Next.js 14 server actions

I'm currently facing a challenge while working on a Next.js 14 project where I am trying to make changes to cookies. Despite carefully following the Next.js documentation regarding server actions and cookie manipulation, I keep running into an error w ...

Angular 16 SSR encounters a TypeError when the 'instanceof' operator is used on a value that is not an object

I have been facing an issue while updating my Angular application from version 15 to 16. Everything seems to work fine with Angular, including building for Angular Universal without any errors. However, when I attempt to serve using npm run serve:ssr, it t ...

Enhance your text in TextInput by incorporating newline characters with advanced editing features

I'm encountering an issue with my Textarea component that handles Markdown headers: type TextareaProps = { initValue: string; style?: StyleProp<TextStyle>; onChange?: (value: string) => void; }; type OnChangeFun = NativeSynthetic ...

Looking to implement Socket.io in a Next.js and Node.js application to send a targeted socket emit to a particular user

I've been working on this issue and have tried various methods, but haven't had any luck so far. Despite reading through a lot of documentation and posts, I can't seem to figure it out. What I need is for a message sent to a specific user ( ...