Consentl mit Next.js
Consentl als erstes im <head> des Root-Layouts im App Router, andere Tags über eine kleine ConsentlScript-Komponente, oder das _document des Pages Router.
- Loader als erstes im <head>
- Ja
Für die vorherige Blockierung und die Standardwerte von Google Consent Mode muss Consentl vor allen
anderen Tags laufen, und zwar synchron (kein async, defer oder type="module"). In Next.js
bedeutet das ein einfaches <script>-Tag, nicht next/script.
<script src="https://api.consentl.com/v1/loader.js?k=SITE_KEY&l=LANG"></script>
Speichern Sie den Website-Schlüssel in einer Umgebungsvariablen wie NEXT_PUBLIC_CONSENTL_SITE_KEY.
Der Schlüssel ist öffentlich, es ist also unbedenklich, ihn dem Browser bereitzustellen. Consent Mode
erfordert den Tarif Pro oder höher, die automatische Blockierung bekannter Tracker den Tarif Business.
App Router (app/layout.tsx)
Getestet mit Next.js 16.4 und React 19.
Was React 19 und Next mit Ihren Tags machen
- React behandelt jedes
<script async src>als Ressource und verschiebt es an den Anfang des<head>, über ein einfaches synchrones Skript, auch wenn Sie es nach Consentl geschrieben haben. Auch die eigenen Skripte von Next kommen zuerst. next/scriptmitstrategy="afterInteractive"(undbeforeInteractive) schreibt ein<link rel="preload">für das Tag in die Seite. Der Browser lädt das Tag herunter, während er die Seite liest – vor der Einwilligung. Consentl verhindert seine Ausführung, aber nicht diese Anfrage.
Die gestreamten Seitendaten von Next (self.__next_f) werden von Consentl nie zurückgehalten, egal,
was darin vorkommt.
Empfohlene Einrichtung
- Consentl als einfaches
<script src>, als erstes im<head>. React verschiebt es nicht, es steht einmal in der Seite, und Besucher erhalten immer Ihre aktuellen Banner-Einstellungen (der Loader wird 5 Minuten zwischengespeichert). - Jedes andere Tag, das auf eine Einwilligung warten muss (Google Analytics, Meta, TikTok…), über die
kleine Komponente
ConsentlScriptunten. Sie schreibt das Tag alstype="text/plain"mit seiner Consentl-Kategorie: React verschiebt es nicht, der Browser lädt es nicht herunter, und Consentl führt es nach der Einwilligung einmal aus, in jedem Tarif, auch nach clientseitiger Navigation. - Oder verwalten Sie diese Tags in Google Tag Manager (siehe Google Tag Manager).
Google-Tags im erweiterten Modus von Consent Mode (ab Tarif Pro) sollen vor der Einwilligung
geladen werden; wenn Sie diesen Modus verwenden, laden Sie sie mit next/script und
afterInteractive. strategy="lazyOnload" schreibt kein Preload (Next 16.4) und wird bis zur
Einwilligung zurückgehalten, aber nur bei Tags, die die automatische Blockierung erkennt (Tarif
Business); verwenden Sie daher vorzugsweise ConsentlScript.
// app/consentl-script.tsx — works in Server and Client Components
type Category = "preferences" | "analytics" | "marketing";
/** A tag that waits for consent: inert in the page, run by Consentl once the category is accepted. */
export function ConsentlScript({ category, src, nonce, children }: { category: Category; src?: string; nonce?: string; children?: string }) {
return src ? (
// eslint-disable-next-line @next/next/no-sync-scripts -- type="text/plain": never loaded by the browser itself
<script type="text/plain" data-consentl={category} src={src} nonce={nonce} />
) : (
<script type="text/plain" data-consentl={category} nonce={nonce} dangerouslySetInnerHTML={{ __html: children ?? "" }} />
);
}
// app/layout.tsx (or app/[locale]/layout.tsx)
import { ConsentlScript } from "./consentl-script";
const SITE_KEY = process.env.NEXT_PUBLIC_CONSENTL_SITE_KEY!;
export default function RootLayout({ children }: { children: React.ReactNode }) {
const lang = "en"; // e.g. (await params).locale
const loader = `https://api.consentl.com/v1/loader.js?k=${encodeURIComponent(SITE_KEY)}&l=${encodeURIComponent(lang)}`;
return (
<html lang={lang}>
<head>
{/* eslint-disable-next-line @next/next/no-sync-scripts -- must block: consent defaults + prior blocking */}
<script src={loader} />
</head>
<body>
{children}
<ConsentlScript category="analytics" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX" />
<ConsentlScript category="analytics">
{`window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','G-XXXXXXX');`}
</ConsentlScript>
<footer>
<a href="#consentl" data-consentl-open="">Cookie settings</a>
</footer>
</body>
</html>
);
}
Mit einer Content Security Policy übergeben Sie Ihre Nonce an ConsentlScript (nonce={nonce});
Consentl behält sie bei, wenn es das Tag ausführt.
Warum den Loader nicht inline ausgeben?
Eine frühere Version dieser Seite hat den Loader auf dem Server abgerufen und inline ausgegeben. Im App
Router sendet das den Loader bei jedem vollständigen Laden der Seite zweimal, weil React den Inhalt
des <script> einer Server Component zusätzlich in die Seitendaten kopiert, und statisch gebaute
Seiten behalten die beim Build abgerufene Kopie, bis sie revalidiert werden. Auf derselben Testseite:
| Einrichtung | HTML der Seite | Consentl-Loader |
|---|---|---|
| Einfaches Script-Tag (empfohlen) | 2,2 KB gzip | 9,5 KB gzip, eine Anfrage, 5 Minuten zwischengespeichert und von allen Seiten gemeinsam genutzt |
| Inline-Loader | 15,2 KB gzip, bei jedem vollständigen Laden der Seite | zweimal in der Seite |
Das einfache Tag kostet eine Anfrage an api.consentl.com, bevor die Seite gerendert wird. Wenn alle
anderen Tags in ConsentlScript (oder Google Tag Manager) stehen, gibt es in der Seite nichts, was der
Browser herunterladen könnte, bevor Consentl läuft.
Nicht empfohlen: beforeInteractive
next/script mit strategy="beforeInteractive" wird als Preload plus Inline-Eintrag in einer
Warteschlange ausgegeben; Next fügt das eigentliche <script> vor der Hydration ein, nach
Inline- und asynchronen Skripten, die bereits im serverseitig gerenderten HTML stehen.
Pages Router (pages/_document.tsx)
Im Pages Router wird beforeInteractive mit defer nach den CSS-Links ausgegeben. Verwenden Sie
stattdessen ein einfaches Skript:
import { Head, Html, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html lang="en">
<Head>
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
<script src={`https://api.consentl.com/v1/loader.js?k=${process.env.NEXT_PUBLIC_CONSENTL_SITE_KEY}&l=en`} />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
Clientseitige Navigation
Es ist nichts weiter nötig: Die Laufzeit bleibt geladen, die Auswahl liegt im First-Party-Cookie
consentl, und Links „Cookie-Einstellungen“ funktionieren auf jeder Route. Prüfen Sie in Ihrem eigenen
Code die Einwilligung mit window.Consentl?.allowed("analytics") und dem Event consentl:change, und
starten Sie alles nur einmal (siehe Jede Website).
Prüfen, ob es funktioniert
Verwenden Sie auf einer Seite die Quelltextansicht (nicht den Element-Inspektor): Nach den eigenen
Skripten /_next/static/chunks/… von Next muss Consentl vor allen anderen Skripten stehen, es gibt
kein <link rel="preload"> für ein Tracking-Tag, und Ihre Tags sind type="text/plain". Öffnen Sie
die Website dann in einem privaten Fenster und prüfen Sie das Banner und den Tab „Network“ wie unter
Jede Website beschrieben: keine Anfrage an einen Tracker, bevor
Sie akzeptieren.
Einschränkungen
- Im Layout geschriebene
async-Tags verschiebt React über Consentl; verwenden Sie stattdessenConsentlScript. next/scriptmitafterInteractivelässt den Browser das Tag vor der Einwilligung herunterladen.- Mit
beforeInteractivelaufen Skripte, die bereits im serverseitig gerenderten HTML stehen, vor Consentl. - Ein Sprachwechsel im Client lädt das Banner nicht neu; die neue Sprache gilt ab dem nächsten vollständigen Laden der Seite.
- Wenn Sie eine Content Security Policy senden, erlauben Sie
https://api.consentl.com(siehe Jede Website).
Verwandte Anleitungen
Kommen Sie nicht weiter? Schreiben Sie an support@consentl.com – wir antworten an Werktagen auf Englisch.