Consent Google Analytics Cookies
Unanswered
Barbary Lion posted this in #help-forum
Barbary LionOP
Hello, I want to add google analytics on my website. I came across
@next/third-parties/google but I didn't found any way to implement a consent message to let the user decide wether they want to accept or decline the cookies.2 Replies
Barbary LionOP
If I uncomment the code, I get the error, that gtag is not a function. How can I solve it? If I run the build command, it tells me that I cannot use useSearchParams without wrapping it inside a Suspense component. But if I wrap it, I get a hydration error...
# GoogleAnalytics.tsx
# layout.tsx
# GoogleAnalytics.tsx
"use client";
// import { useSearchParams, usePathname } from "next/navigation";
import { GoogleTagManager } from "@next/third-parties/google";
import { useEffect, useState } from "react";
type GoogleAnalyticsProps = {
gtmId: string;
};
export const GoogleAnalytics = ({ gtmId }: GoogleAnalyticsProps) => {
const [allowGoogleTracking, setAllowGoogleTracking] = useState(false);
// const pathname = usePathname();
// const searchParams = useSearchParams();
useEffect(() => {
const allowTracking = localStorage.getItem("allowGoogleTracking") ?? "false";
if (allowTracking === "true") setAllowGoogleTracking(true);
// const url = pathname + searchParams.toString();
// console.log(url);
// window.gtag("config", gtmId, {
// page_path: url
// });
}, []);
return allowGoogleTracking && <GoogleTagManager gtmId={gtmId} />;
};# layout.tsx
import "@/app/globals.scss";
import { Inter as FontSans } from "next/font/google";
import { TailwindIndicator } from "@/components/TailwindIndicator";
import { generateMetadata, generateViewport } from "@/lib/meta";
import { GoogleAnalytics } from "@/components/GoogleAnalytics";
import { CookieBanner } from "@/components/CookieBanner";
import { ScrollTop } from "@/components/ScrollTop";
import { Toaster } from "@/components/ui/toaster";
import { cn } from "@/lib/utils";
const fontSans = FontSans({
subsets: ["latin"],
variable: "--font-inter"
});
export default async function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<head>
<GoogleAnalytics gtmId={process.env.NEXT_PUBLIC_GTM_ID} />
</head>
<body
suppressHydrationWarning={true}
className={cn("no-scrollbar h-dvh min-h-dvh overflow-y-auto bg-background font-sans antialiased", fontSans.variable)}
>
<div id="top" className="relative flex h-dvh min-h-dvh flex-col">
{children}
</div>
<TailwindIndicator />
<CookieBanner />
<ScrollTop />
<Toaster />
</body>
</html>
);
}
export const metadata = generateMetadata();
export const viewport = generateViewport();Highlander
I've strungled with cookie consent on nextjs also, I still was not able to manage consent (setting default, and update) using @next/third-party/google so this is how I manage consnet on my Next.js 15 project. Tested with Google Tag Assistant
Then to update consent
'use client';
import Script from 'next/script';
import { useEffect, useState } from 'react';
export default function GoogleTag({ GA_ID }: { GA_ID: string }) {
const [consent, setConsent] = useState<string | null>(null);
useEffect(() => {
// Set the consent value after the client loaded to avoid errors.
setConsent(localStorage.getItem('cookie') === "true" ? 'granted' : 'denied');
}, [GA_ID]);
if (consent === null) return null;
return (
<>
<Script
strategy="afterInteractive"
src={https://www.googletagmanager.com/gtag/js?id=${GA_ID}}
/>
<Script
id="google-tag-manager"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html:
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('consent', 'default', {
'ad_storage': '${consent}',
'ad_user_data': '${consent}',
'ad_personalization': '${consent}',
'analytics_storage': '${consent}'
});
gtag('config', '${GA_ID}', {
page_path: window.location.pathname,
});
,
}}
/>
</>
);
}Then to update consent
useEffect(() => {
// Don't update consent on first render
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
window.gtag("consent", "update", {
ad_storage: local ? "granted" : "denied",
ad_user_data: local ? "granted" : "denied",
ad_personalization: local ? "granted" : "denied",
analytics_storage: local ? "granted" : "denied",
});
}, [local]);