Consentl con Next.js
Coloque Consentl el primero en el <head> del layout raíz del App Router, cargue las demás etiquetas con ConsentlScript o use el _document del Pages Router.
- Cargador el primero en el <head>
- Sí
Para el bloqueo previo y los valores predeterminados de Google Consent Mode, Consentl debe ejecutarse
antes que cualquier otra etiqueta, de forma síncrona (sin async, defer ni type="module").
En Next.js, eso significa una etiqueta <script> simple, no next/script.
<script src="https://api.consentl.com/v1/loader.js?k=SITE_KEY&l=LANG"></script>
Guarde la clave del sitio en una variable de entorno como NEXT_PUBLIC_CONSENTL_SITE_KEY. La clave es
pública, así que no hay problema en exponerla al navegador. Consent Mode requiere el plan Pro o
superior; el bloqueo automático de rastreadores conocidos, el plan Business.
App Router (app/layout.tsx)
Probado con Next.js 16.4 y React 19.
Qué hacen React 19 y Next con sus etiquetas
- React trata cada
<script async src>como un recurso y lo traslada al principio del<head>, por encima de un script síncrono simple, aunque lo haya escrito después de Consentl. Los propios scripts de Next también van primero. next/scriptconstrategy="afterInteractive"(ybeforeInteractive) escribe en la página un<link rel="preload">para la etiqueta. El navegador descarga la etiqueta mientras lee la página, antes del consentimiento. Consentl impide que se ejecute, pero no esa solicitud.
Consentl nunca retiene los datos de página transmitidos en streaming por Next (self.__next_f), sea
cual sea su contenido.
Configuración recomendada
- Consentl como
<script src>simple, el primero en el<head>. React no lo traslada, aparece una sola vez en la página y los visitantes siempre reciben la configuración actual de su banner (el cargador se almacena en caché durante 5 minutos). - Todas las demás etiquetas que deben esperar el consentimiento (Google Analytics, Meta, TikTok…)
mediante el pequeño componente
ConsentlScriptde abajo. Escribe la etiqueta comotype="text/plain"con su categoría de Consentl: React no la traslada, el navegador no la descarga y Consentl la ejecuta una vez después del consentimiento, en todos los planes, también tras la navegación en el lado del cliente. - O gestione esas etiquetas en Google Tag Manager (consulte Google Tag Manager).
Las etiquetas de Google en el modo avanzado de Consent Mode (plan Pro y superiores) están pensadas
para cargarse antes del consentimiento; si utiliza ese modo, cárguelas con next/script y
afterInteractive. strategy="lazyOnload" no escribe ningún preload (Next 16.4) y se retiene hasta el
consentimiento, pero solo para las etiquetas que reconoce el bloqueo automático (plan Business), así
que es preferible 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>
);
}
Con una Content Security Policy, pase su nonce a ConsentlScript (nonce={nonce}); Consentl lo
conserva al ejecutar la etiqueta.
¿Por qué no imprimir el cargador en línea?
Una versión anterior de esta página obtenía el cargador en el servidor y lo imprimía en línea. En el
App Router, eso envía el cargador dos veces en cada carga completa de página, porque React también
copia el contenido del <script> de un Server Component en los datos de la página, y las páginas
generadas de forma estática conservan la copia obtenida durante la compilación hasta que se revalidan.
En la misma página de prueba:
| Configuración | HTML de la página | Cargador de Consentl |
|---|---|---|
| Etiqueta script simple (recomendado) | 2,2 KB comprimido con gzip | 9,5 KB comprimido con gzip, una solicitud, en caché durante 5 minutos y compartido por todas las páginas |
| Cargador en línea | 15,2 KB comprimido con gzip, en cada carga completa de página | dos veces en la página |
La etiqueta simple cuesta una solicitud a api.consentl.com antes de que se muestre la página. Con
todas las demás etiquetas en ConsentlScript (o en Google Tag Manager), no hay nada en la página que
el navegador pueda descargar antes de que se ejecute Consentl.
No recomendado: beforeInteractive
next/script con strategy="beforeInteractive" se emite como un preload más una entrada de cola en
línea; Next inserta el <script> real antes de la hidratación, después de los scripts en línea y
asíncronos que ya están en el HTML generado en el servidor.
Pages Router (pages/_document.tsx)
En el Pages Router, beforeInteractive se genera con defer después de los enlaces CSS. Utilice en su
lugar un script simple:
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>
);
}
Navegación en el lado del cliente
No hace falta nada más: el runtime permanece cargado, la elección se guarda en la cookie propia
consentl y los enlaces «Configuración de cookies» funcionan en cualquier ruta. Para su propio código,
compruebe el consentimiento con window.Consentl?.allowed("analytics") y el evento consentl:change,
e inicie las cosas una sola vez (consulte Cualquier sitio web).
Comprobar que funciona
Utilice Ver código fuente (no el inspector de elementos) en una página: después de los propios
scripts /_next/static/chunks/… de Next, Consentl debe ir antes que cualquier otro script, no hay
ningún <link rel="preload"> para una etiqueta de seguimiento y sus etiquetas son type="text/plain".
Después, abra el sitio en una ventana privada y compruebe el banner y la pestaña Network como se
describe en Cualquier sitio web: ninguna solicitud a un
rastreador antes de aceptar.
Limitaciones
- React traslada por encima de Consentl las etiquetas
asyncescritas en el layout; utilice en su lugarConsentlScript. next/scriptconafterInteractivehace que el navegador descargue la etiqueta antes del consentimiento.- Con
beforeInteractive, los scripts que ya están en el HTML generado en el servidor se ejecutan antes que Consentl. - Un cambio de idioma en el lado del cliente no recarga el banner; el nuevo idioma se aplica en la siguiente carga completa de página.
- Si envía una Content Security Policy, permita
https://api.consentl.com(consulte Cualquier sitio web).
Guías relacionadas
¿Se ha atascado? Escriba a support@consentl.com: respondemos en inglés en días laborables.