Consentl cu Next.js

Plasați Consentl primul în <head> al layoutului rădăcină din App Router, încărcați alte etichete prin ConsentlScript sau folosiți _document din Pages Router.

Scriptul de încărcare primul în <head>
Da

Pentru blocarea prealabilă și valorile implicite Google Consent Mode, Consentl trebuie să ruleze înaintea oricărei alte etichete, sincron (fără async, defer sau type="module"). În Next.js, aceasta înseamnă o etichetă <script> simplă, nu next/script.

<script src="https://api.consentl.com/v1/loader.js?k=SITE_KEY&l=LANG"></script>

Stocați cheia site-ului într-o variabilă de mediu, cum ar fi NEXT_PUBLIC_CONSENTL_SITE_KEY. Cheia este publică, așa că expunerea ei în browser nu este o problemă. Consent Mode necesită planul Pro sau unul superior, iar blocarea automată a trackerelor cunoscute planul Business.

App Router (app/layout.tsx)

Testat cu Next.js 16.4 și React 19.

Ce fac React 19 și Next cu etichetele dumneavoastră

  • React tratează fiecare <script async src> ca pe o resursă și o mută în partea de sus a <head>, deasupra unui script sincron simplu, chiar dacă l-ați scris după Consentl. Și scripturile proprii ale Next vin primele.
  • next/script cu strategy="afterInteractive" (și beforeInteractive) scrie în pagină un <link rel="preload"> pentru etichetă. Browserul descarcă eticheta în timp ce citește pagina, înainte de consimțământ. Consentl împiedică rularea ei, dar nu și această solicitare.

Datele de pagină transmise în flux de Next (self.__next_f) nu sunt reținute niciodată de Consentl, indiferent ce menționează.

  1. Consentl ca <script src> simplu, primul în <head>. React nu îl mută, apare o singură dată în pagină, iar vizitatorii primesc întotdeauna setările actuale ale bannerului (scriptul de încărcare este păstrat în cache 5 minute).
  2. Fiecare altă etichetă care trebuie să aștepte consimțământul (Google Analytics, Meta, TikTok…) prin mica componentă ConsentlScript de mai jos. Aceasta scrie eticheta ca type="text/plain" cu categoria sa Consentl: React nu o mută, browserul nu o descarcă, iar Consentl o rulează o singură dată după consimțământ, în orice plan, inclusiv după navigarea pe client.
  3. Sau administrați aceste etichete în Google Tag Manager (consultați Google Tag Manager).

Etichetele Google în modul avansat Consent Mode (planul Pro și cele superioare) sunt concepute să se încarce înainte de consimțământ; dacă folosiți acest mod, încărcați-le cu next/script și afterInteractive. strategy="lazyOnload" nu scrie niciun preload (Next 16.4) și este reținut până la consimțământ, dar doar pentru etichetele recunoscute de blocarea automată (planul Business), așa că preferați 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>
  );
}

Cu o Content Security Policy, transmiteți nonce-ul către ConsentlScript (nonce={nonce}); Consentl îl păstrează atunci când rulează eticheta.

De ce să nu afișați scriptul de încărcare inline?

O versiune anterioară a acestei pagini prelua scriptul de încărcare pe server și îl afișa inline. În App Router, aceasta trimite scriptul de încărcare de două ori la fiecare încărcare completă a paginii, deoarece React copiază și conținutul unui <script> dintr-o Server Component în datele paginii, iar paginile construite static păstrează copia preluată la build până când sunt revalidate. Pe aceeași pagină de test:

Configurare HTML-ul paginii Scriptul de încărcare Consentl
Etichetă script simplă (recomandat) 2,2 KB gzip 9,5 KB gzip, o solicitare, păstrat în cache 5 minute și partajat de toate paginile
Script de încărcare inline 15,2 KB gzip, la fiecare încărcare completă a paginii de două ori în pagină

Eticheta simplă costă o solicitare către api.consentl.com înainte de afișarea paginii. Cu toate celelalte etichete în ConsentlScript (sau în Google Tag Manager), în pagină nu există nimic pe care browserul să îl poată descărca înainte să ruleze Consentl.

next/script cu strategy="beforeInteractive" este emis ca un preload plus o intrare inline într-o coadă; Next inserează <script>-ul real înainte de hidratare, după scripturile inline și asincrone deja prezente în HTML-ul generat pe server.

Pages Router (pages/_document.tsx)

În Pages Router, beforeInteractive este afișat cu defer după linkurile CSS. Folosiți în schimb un script simplu:

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>
  );
}

Navigarea pe client

Nu este nevoie de nimic suplimentar: runtime-ul rămâne încărcat, alegerea se află în cookie-ul propriu consentl, iar linkurile „Setări cookie-uri” funcționează pe orice rută. Pentru propriul cod, verificați consimțământul cu window.Consentl?.allowed("analytics") și evenimentul consentl:change și porniți lucrurile o singură dată (consultați Orice site).

Verificați că funcționează

Folosiți View Source (nu inspectorul de elemente) pe o pagină: după scripturile proprii ale Next /_next/static/chunks/…, Consentl trebuie să vină înaintea oricărui alt script, nu există niciun <link rel="preload"> pentru o etichetă de urmărire, iar etichetele dumneavoastră sunt type="text/plain". Apoi deschideți site-ul într-o fereastră privată și verificați bannerul și fila Network așa cum este descris în Orice site: nicio solicitare către un tracker înainte să acceptați.

Limitări

  • Etichetele async scrise în layout sunt mutate de React deasupra Consentl; folosiți în schimb ConsentlScript.
  • next/script cu afterInteractive face ca browserul să descarce eticheta înainte de consimțământ.
  • Cu beforeInteractive, scripturile deja prezente în HTML-ul generat pe server rulează înaintea Consentl.
  • O schimbare de limbă pe client nu reîncarcă bannerul; noua limbă se aplică la următoarea încărcare completă a paginii.
  • Dacă trimiteți o Content Security Policy, permiteți https://api.consentl.com (consultați Orice site).

V-ați blocat? Scrieți-ne la support@consentl.com — răspundem în limba engleză, în zilele lucrătoare.