Cookie-Einwilligung für Next.js, Gatsby und statische Seiten: Ein Integrationsleitfaden für Entwickler
Das Einwilligungsproblem bei statischen Seiten
Moderne JavaScript-Frameworks wie Next.js, Gatsby und Nuxt.js haben einen Paradigmenwechsel in der Art und Weise eingeleitet, wie Webseiten erstellt und ausgeliefert werden. Seiten werden zur Build-Zeit oder auf dem Server vorgerendert und anschließend auf dem Client hydratisiert. Das schafft eine besondere Herausforderung für Cookie-Einwilligungen: Das Einwilligungsbanner muss bereit sein, bevor Tracking-Skripte ausgeführt werden, aber die Seite selbst kann bereits gerendert und am Edge gecacht sein.
Traditionelle CMPs wurden für servergerenderte PHP- oder einfache HTML-Seiten entwickelt, bei denen das Dokument linear von oben nach unten geladen wird. In einer Framework-Welt mit Code-Splitting, Lazy Loading und Streaming-Server-Side-Rendering brechen diese Annahmen weg. Einwilligung in diesen Umgebungen korrekt umzusetzen, erfordert ein Verständnis der Rendering-Pipeline.
Warum Timing wichtiger ist, als Sie denken
In einer klassischen HTML-Seite ist es einfach, ein CMP-Skript im <head> vor anderen Skripten zu platzieren. In Next.js App Router oder Gatsby ist die Situation komplexer:
- Vorrenderte HTML kommt zuerst: Der Browser erhält vollständiges HTML vom CDN oder Server. Wenn Inline-Skripte oder Third-Party-Tags in dieses HTML eingebettet sind, können sie ausgeführt werden, bevor Ihre Einwilligungslogik geladen ist.
- Hydration-Gap: Die React-Hydration findet statt, nachdem das HTML gerendert wurde. Wenn Ihre Einwilligungskomponente eine React-Komponente ist, existiert sie erst in einem funktionsfähigen Zustand, wenn die Hydration abgeschlossen ist. In dieser Lücke können Google-Tags oder Analytics-Skripte ohne Einwilligung feuern.
- Edge-Caching-Komplikationen: Wenn Sie ISR (Incremental Static Regeneration) oder Edge Functions verwenden, wird das HTML gecacht. Sie können einwilligungsabhängige Logik nicht dynamisch in gecachtes HTML injizieren, ohne einen Client-seitigen Mechanismus.
Das zentrale Prinzip lautet: Einwilligung muss auf Skript-Ebene, nicht auf Komponenten-Ebene sichergestellt werden. Eine React-Komponente, die ein Einwilligungsbanner rendert, kommt zu spät, wenn sie erst nach der Hydration interaktiv wird.
Integration mit dem Next.js App Router
Next.js 13+ mit dem App Router hat einen neuen Weg eingeführt, Skripte zu handhaben. So gehen Sie bei der Einwilligungsintegration vor:
Schritt 1: CMP-Skript im Root-Layout laden
Verwenden Sie die Next.js-Script-Komponente mit der Strategie beforeInteractive in Ihrem Root-layout.tsx. Das weist Next.js an, das Skript in das initiale HTML-Dokument zu injizieren, bevor die Hydration beginnt:
Die Strategie beforeInteractive ist entscheidend. Die Standardstrategie afterInteractive lädt Skripte nach der Hydration – das ist für Einwilligung zu spät. Mit beforeInteractive wird das CMP-Skript in das servergerenderte HTML aufgenommen und beim Laden der Seite ausgeführt.
Schritt 2: Standard-Einwilligung vor Google-Tags setzen
Fügen Sie vor Ihrem Google Tag Manager- oder gtag.js-Snippet ein Inline-Skript ein, das Standard-Einwilligungszustände setzt. So wird sichergestellt, dass GTM selbst dann die verweigerten Defaults respektiert, wenn es vor dem CMP-Banner geladen wird:
Dieses Inline-Skript sollte im <head> Ihres Root-Layouts platziert werden, vor den CMP- und GTM-Skripten. In Next.js können Sie dafür ein normales <script>-Tag innerhalb des <head>-Elements Ihres Layouts verwenden.
Schritt 3: Routenwechsel behandeln
Bei Single-Page-Application-Navigation wird das CMP-Skript nur einmal geladen, aber Routenwechsel lösen keinen vollständigen Seiten-Reload aus. Ihr CMP muss über Client-seitige Navigationsvorgänge hinweg bestehen bleiben. FlexyConsent erledigt dies automatisch – einmal geladen, bleibt es über alle Routenwechsel hinweg aktiv, ohne erneut initialisiert werden zu müssen.
Integration mit dem Next.js Pages Router
Für Projekte, die noch den Pages Router verwenden, ist der Ansatz ähnlich, nutzt aber _document.tsx statt des Root-Layouts. Platzieren Sie das CMP-Skript in der <Head>-Komponente Ihrer benutzerdefinierten Document-Klasse. Die Strategie beforeInteractive funktioniert im Pages Router genauso.
Der entscheidende Unterschied ist, dass _document.tsx nur auf dem Server gerendert wird. Damit ist jede Einwilligungslogik hier garantiert Teil des initialen HTML-Payloads.
Gatsby-Integration für statische Seiten
Gatsby generiert vollständig statisches HTML zur Build-Zeit. Es gibt kein Server-Side-Rendering zur Request-Zeit, was einige Aspekte vereinfacht, andere aber verkompliziert:
- Verwenden Sie
gatsby-ssr.tsx, um das CMP-Skript in den<head>jeder Seite zu injizieren. DieonRenderBody-API ermöglicht es Ihnen, Skripte in den Head einzufügen, die in jeder statischen HTML-Datei vorhanden sein werden. - Vermeiden Sie Gatsby-Plugins, die Einwilligung lazy-loaden: Einige Community-Plugins kapseln Einwilligung in React-Komponenten, die erst nach der Hydration gemountet werden. Das erzeugt die oben beschriebene Timing-Lücke.
- Standard-Einwilligung inline platzieren: Verwenden Sie
setHeadComponentsingatsby-ssr.tsx, um ein Inline-Skript hinzuzufügen, das Standard-Einwilligungszustände setzt. Dieses Skript wird im statischen HTML enthalten sein und sofort ausgeführt.
Der Build-Time-Ansatz von Gatsby bedeutet, dass jede HTML-Datei auf Ihrem CDN das Einwilligungsskript enthält. Das ist tatsächlich ideal – es gibt keine Serverlogik, die fehlschlagen oder falsch cachen könnte.
Nuxt.js-spezifische Aspekte
Nuxt.js (Vue-basiert) hat eigene Muster. In Nuxt 3 verwenden Sie das useHead-Composable oder die nuxt.config.ts-App-Head-Konfiguration, um das CMP-Skript global hinzuzufügen. Nuxt unterstützt eine Option body: false (platziert Skripte im Head) und ein async-Attribut für nicht-blockierendes Laden.
Für den Server-Side-Rendering-Modus von Nuxt gilt dasselbe Prinzip: Das CMP-Skript muss in der initialen HTML-Antwort enthalten sein und darf nicht erst von einer Vue-Komponente nach dem Mount dynamisch injiziert werden.
Layout-Shift vermeiden
Einwilligungsbanner sind berüchtigt dafür, Cumulative Layout Shift (CLS) zu verursachen – eine Core Web Vital-Kennzahl, die sich auf SEO-Rankings auswirkt. Wenn ein Banner erst nach dem Rendern der Seite erscheint, verschiebt es Inhalte nach unten oder überlagert sie unerwartet.
Strategien zur Minimierung von CLS durch Einwilligungsbanner:
- Banner am unteren Rand verwenden: Banner am unteren Rand des Viewports verschieben keine Seiteninhalte. Das ist der CLS-freundlichste Ansatz.
- Platz reservieren: Wenn Sie ein Banner oben verwenden müssen, reservieren Sie den vertikalen Platz in Ihrem CSS, sodass das Seitenlayout das Banner bereits vor dem Rendern berücksichtigt.
- Vermeiden Sie Modals beim Laden: Vollbild-Einwilligungswände, die nach dem Rendern der Seite erscheinen, verursachen wahrgenommene Layoutinstabilität. Wenn Sie eine Wall benötigen, rendern Sie sie als Teil des initialen Seitenzustands.
- CMP synchron im Head laden: Wenn das CMP als render-blockierendes Skript im Head geladen wird, kann das Banner Teil des initialen Paints sein, statt später „hineinzuspringen“.
Der Framework-agnostische Ansatz von FlexyConsent
FlexyConsent wurde so entwickelt, dass es mit jedem Framework – oder ganz ohne Framework – funktioniert, indem es auf Skript-Ebene statt auf Komponenten-Ebene arbeitet. Warum das wichtig ist:
- Ein einziges asynchrones Script-Tag: Ein
<script>-Tag im<head>genügt. Keine npm-Pakete, keine Framework-spezifischen Wrapper, keine Build-Konfiguration. - Einwilligungs-Defaults feuern sofort: Das Skript setzt Consent Mode V2-Defaults als erste Aktion, noch bevor irgendein Callback oder DOM-Manipulation stattfindet. So respektieren Google-Tags die Einwilligung ab der ersten Millisekunde.
- Keine DOM-Abhängigkeit: Die Einwilligungslogik wartet nicht darauf, dass React, Vue oder Svelte hydrieren. Sie arbeitet unabhängig vom Framework-Lifecycle.
- Funktioniert mit SSG, SSR, ISR und CSR: Da es sich um ein einfaches Skript handelt, funktioniert es identisch, egal ob die Seite statisch generiert, servergerendert, inkrementell regeneriert oder Client-seitig gerendert wurde.
Developer-Tipp: Der einfachste Test für eine korrekte CMP-Integration ist, den Network-Tab Ihres Browsers zu öffnen, nach Google-Domains zu filtern und die Seite neu zu laden. Es sollten keine Google-Requests feuern, bevor der Befehl zum Setzen der Einwilligungs-Defaults in der Konsole erscheint. Wenn doch, lädt Ihr CMP zu spät.
Der kostenlose Plan von FlexyConsent unterstützt unbegrenzte Pageviews und funktioniert mit Next.js, Gatsby, Nuxt, Astro, SvelteKit, Remix und einfachem HTML. Die Integration ist in allen Fällen gleich: ein Script-Tag, korrekt platziert.