Implementierung von NextJS Cookie Consent Google Tag Manager Google Analytics

Table of Contents

Intro

Dieser Leitfaden führt dich durch die Implementierung eines GDPR-konformen Google Analytics-Setups mit Google Tag Manager (GTM) in Next.js 15, TypeScript, komplett mit einem Cookie-Consent-System.

Was ist GDPR Compliance?

Die Allgemeine Datenschutzverordnung (GDPR) verlangt von Websites, dass sie:
  • vor der Erhebung von Nutzerdaten die ausdrückliche Zustimmung einzuholen
  • den Nutzern die Möglichkeit zu geben, sich gegen eine nicht unbedingt notwendige Tracking zu entscheiden
  • klare Informationen über die Datenerfassung bereitstellen
  • den Nutzern die Möglichkeit zu geben, ihre Präferenzen jederzeit zu ändern

Was ist Google Tag Manager (GTM)?

GTM ist ein Tag-Management-System, mit dem Sie:

  • Einsatz verschiedener Tracking-Skripte (Tags)
  • Mehrere Analysetools zu verwalten
  • Steuern, wann und wie Tags je nach Zustimmung des Nutzers ausgelöst werden
  • Tracking-Implementierungen zu aktualisieren, ohne den Code zu ändern

Was ist Google Analytics 4 (GA4)?

GA4 ist die neueste Analyseplattform von Google, die:
  • Bietet erweiterte Datenschutzfunktionen
  • Unterstützt den Zustimmungsmodus
  • Bietet flexible Optionen für die Datenerfassung
  • Arbeitet nahtlos mit GTM zusammen

Implementierungsguide

Setup der Dependencies

Ich benutze das Paket vanilla-cookieconsent. Es wird mit einem vordefinierten Design geliefert.
Füge zunächst das erforderliche Package zu Ihrem Next.js-Projekt hinzu:
				
					yarn add vanilla-cookieconsent
				
			

GTM mit Default Denied State initialisieren

Initialisiere in deiner Next.js-Layoutdatei GTM, wobei das Tracking standardmäßig deaktiviert ist. Vergesse nicht die GTM-ID einzustellen
				
					// app/layout.tsx
import Script from 'next/script';

export default function RootLayout({ children }) {
  return (
    <html>
      <head>
        <Script id='gtm-script' strategy='afterInteractive'>
            {`
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('consent', 'default', {
              'ad_storage': 'denied',
              'analytics_storage': 'denied',
              'personalization_storage': 'denied',
              'functionality_storage': 'denied',
              'ad_user_data': 'denied',
              'ad_personalization': 'denied',
            });
            (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
            'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
            })(window,document,'script','dataLayer','YOUR GTM ID');
          `}
          </Script>
      </head>
      <body>{children}</body>
    </html>
  );
}
				
			

Cookie Consent Banner implementieren

Erstelle eine Cookie Consent Komponente, die:
  • Zeige einen Link zu deinem Datenschutzhinweis an
  • Ermöglicht eine granulare Auswahl an Einwilligungen (Alle akzeptieren, Nur Notwendiges, Manuelle Einstellung)
  • Aktualisiert den GTM-Einwilligungsstatus auf der Grundlage der vom Benutzer getroffenen Entscheidungen
  • Implementiere die Logik zur Aktualisierung der Einwilligung
  • Stelle sicher deine Domäne festzulegen oder verwende eine Umgebungsvariable (Zeile 62)
				
					// components/CookieConsent.tsx
'use client';

import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import 'vanilla-cookieconsent/dist/cookieconsent.css';
import * as CookieConsent from 'vanilla-cookieconsent';

interface CookieConsentContextType {
  acceptedServices: string[];
}

const CookieConsentContext = createContext<CookieConsentContextType | undefined>(undefined);

export const useCookieConsent = (): CookieConsentContextType => {
  const context = useContext(CookieConsentContext);
  if (!context) {
    throw new Error('useCookieConsent must be used within a CookieConsentProvider');
  }
  return context;
};

interface CookieConsentProviderProps {
  children: ReactNode;
}

export const CookieConsentProvider: React.FC<CookieConsentProviderProps> = ({ children }) => {
  const [acceptedServices, setAcceptedServices] = useState<string[]>([]);

  useEffect(() => {
    const updateGtmConsent = () => {
      if (typeof window.gtag !== 'function') return;

      const userPreferences = CookieConsent.getUserPreferences();
      const acceptedCategories: string[] = userPreferences.acceptedCategories || [];
      const acceptedServices = userPreferences.acceptedServices || {};

      // Check if analytics category is accepted AND google is specifically enabled
      const isGoogleAccepted = acceptedCategories.includes('analytics') &&
        acceptedServices.analytics?.includes('google');

      const consentUpdate = {
        analytics_storage: isGoogleAccepted ? 'granted' : 'denied',
        ad_storage: isGoogleAccepted ? 'granted' : 'denied',
        personalization_storage: isGoogleAccepted ? 'granted' : 'denied',
        functionality_storage: 'granted',
        ad_user_data: isGoogleAccepted ? 'granted' : 'denied',
        ad_personalization: isGoogleAccepted ? 'granted' : 'denied',
      };

      window.gtag('consent', 'update', consentUpdate);
    };

    const updateAcceptedServices = () => {
      const userPreferences = CookieConsent.getUserPreferences();
      const acceptedServices = userPreferences.acceptedServices || [];
      const acceptedServicesList = Object.values(acceptedServices).flat();
      setAcceptedServices(acceptedServicesList);
    };

    CookieConsent.run({
      cookie: {
        domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN || 'your-domain.com',
      },
      guiOptions: {
        consentModal: { layout: 'cloud' },
      },
      categories: {
        necessary: {
          enabled: true,
          readOnly: true,
        },
        analytics: {
          services: {
            google: { label: 'Google Analytics' },
          },
        },
      },
      language: {
        default: 'en',
        translations: {
          en: {
            consentModal: {
              title: 'Privacy Settings',
              description: 'We use cookies to enhance your experience. Please choose your preferences.',
              acceptAllBtn: 'Accept all',
              acceptNecessaryBtn: 'Accept only necessary cookies',
              showPreferencesBtn: 'Manage preferences',
            },
            preferencesModal: {
              title: 'Cookie Preferences',
              sections: [
                {
                  title: 'Necessary',
                  description: 'Required for the site to function.',
                  linkedCategory: 'necessary',
                },
                {
                  title: 'Analytics',
                  description: 'Helps us understand site usage.',
                  linkedCategory: 'analytics',
                },
              ],
              acceptAllBtn: 'Accept all',
              acceptNecessaryBtn: 'Accept only necessary cookies',
              savePreferencesBtn: 'Save preferences',
            },
          },
        },
      },
      onChange: () => {
        updateAcceptedServices();
        updateGtmConsent();
      },
      onFirstConsent: () => {
        updateAcceptedServices();
        updateGtmConsent();
      },
    });

    const existingPreferences = CookieConsent.getUserPreferences();
    if (existingPreferences && existingPreferences.acceptedCategories) {
      updateAcceptedServices();
      updateGtmConsent();
    }
  }, []);

  return <CookieConsentContext.Provider value={{ acceptedServices }}>{children}</CookieConsentContext.Provider>;
};
				
			

Verwende den CookieConsentProvider

				
					// app/providers.tsx
'use client';

import { CookieConsentProvider } from '@/components/CookieConsent';

interface ProvidersProps {
  children: React.ReactNode;
}

export default function Providers({ children }: ProvidersProps) {
  return (
    <CookieConsentProvider>
      {children}
    </CookieConsentProvider>
  );
}
				
			

Verwende den Provider in layout

Verwende den Provider code in unserer Layout File

				
					// app/layout.tsx
import Providers from '@/app/providers';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <Script id="gtm-script" strategy="afterInteractive">
          {`
            // Your GTM initialization code here
          `}
        </Script>
      </head>
      <body>
        <Providers>
          {children}
        </Providers>
      </body>
    </html>
  );
}
				
			

Wie füge ich weitere Tracking Services zu meinem Cookie Consent?

  1. Füge einen neuen Server zB in der Analytics Kategorie in der  CookieConsent.run() Funktion
  2. Erstelle eine neue Funktion e.g. updateXConsent()
    1. Füge dann usage in onChange und onFirstConsent ein
  3. Update deinen Modal Text wenn du eine neue Kategorie hinzufügst

Füge eine Privacy Seite zu seiner NextJS App

Ein wichtiger Aspekt bei der Verwaltung der Cookie-Zustimmung ist es, den Nutzern einen einfachen Zugang zu ihren Datenschutzeinstellungen zu ermöglichen, nachdem sie ihre erste Wahl getroffen haben. Hier eine Beispiel Datenschutz Seite:
				
					// app/settings/privacy/page.tsx
'use client';

import { Button, Stack, Text } from '@mantine/core'; // or any UI library
import * as CookieConsent from 'vanilla-cookieconsent';

export default function PrivacyPage() {
  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold mb-6">Privacy Settings</h1>

      {/* Cookie Settings */}
      <div className="mb-8 p-4 border rounded-lg">
        <h2 className="text-xl font-semibold mb-4">Cookie Settings</h2>
        
        <Stack gap="md">
          <Text>
            Control how we use cookies on our website. Click the button below
            to manage your cookie preferences.
          </Text>

          <Button
            onClick={() => CookieConsent.showPreferences()}
            className="w-fit"
          >
            Manage Cookies
          </Button>
        </Stack>
      </div>
    </div>
  );
}
				
			

Zusammenfassung

Die Implementierung von GDPR-konformen Analysen erfordert eine sorgfältige Beachtung:
  • Datenschutzrechte der Nutzer
  • Technische Umsetzung
  • Verwaltung von Einwilligungen
  • Praktiken der Datenverarbeitung

Wenn Du diesen Leitfaden befolgst, hast du eine robuste, konforme Analyseeinrichtung geschaffen, die die Privatsphäre der Nutzer respektiert und gleichzeitig wertvolle Einblicke in die Nutzung deiner Anwendung bietet.

Links

Gruß, Julian

Portrait Julian Geißler

Über mich

Aus dem Rhein-Main-Gebiet für Kunden deutschlandweit

Mit Wurzeln in der Technologieregion zwischen Frankfurt, Darmstadt, Mannheim und Worms biete ich professionelle Webentwicklung und Software Entwicklung primär remote für Kunden in ganz Deutschland. Bei Bedarf bin ich für wichtige Meetings aber auch persönlich in der Rhein Main Region verfügbar.

Julian Geißler - Programmierer

Mit über 5 Jahren Erfahrung und einem Master in Informatik biete ich Ihnen technische Expertise und direkten Austausch. Mein Fokus liegt auf skalierbaren Lösungen mit Next.js, React, Laravel und Django, ergänzt durch KI Integration und technisches SEO. Von der Konzeption über die Entwicklung bis zum Hosting begleite ich Ihr Projekt mit maßgeschneiderten Lösungen und einem klaren Blick für Ihre geschäftlichen Anforderungen.

Meine Region in Hessen: Frankfurt, Darmstadt, Mannheim und Worms

Kontakt

Sprechen Sie mich an
Als Full Stack Entwickler aus dem Rhein-Main-Gebiet unterstütze ich Sie bei der Umsetzung Ihrer digitalen Ideen

Meine Socials