Consentimiento de cookies para React Router y Remix

En modo framework, root.tsx renderiza el documento, así que la etiqueta va en su Layout, la primera del <head>. Se renderiza en servidor, así que se ejecuta antes de la hidratación y de cualquier rastreador. Los consentimientos que piden tus formularios se registran desde una action, en el servidor.

Configúralo con tu agente de IA

Conecta el servidor MCP de Croombit a tu editor o agente de código y pega esto. Crea el sitio, las categorías de cookies y el banner, y edita tu código.

Con Croombit: crea un sitio para este proyecto y mantén las categorías de cookies que trae. Escribe el texto del banner y publícalo. Crea una clave publicable de TEST para localhost:3000. Es una app React Router v7 en modo framework: añade el <script> de cmp.js al principio del <head> del Layout en app/root.tsx, con la clave de VITE_CROOMBIT_KEY, y registra la casilla de newsletter de nuestra action de alta con @croombit/sdk y CROOMBIT_SECRET_KEY.

El agente trabaja en TEST. Pasar a LIVE son dos pasos en la consola: verificar tu dominio y cambiar a una clave LIVE; consulta pasar a LIVE.

O a mano

1. Añade la etiqueta a root.tsx

Pon la clave en .env como VITE_CROOMBIT_KEY. Una app Remix v2 tiene la misma exportación Layout en app/root.tsx.

// app/root.tsx
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router';

export function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        {/* Server-rendered first in <head>, so it runs before any tracker */}
        <script src="https://croombit.com/cmp.js" data-tc-api-key={import.meta.env.VITE_CROOMBIT_KEY} />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

export default function App() {
  return <Outlet />;
}

2. Retén los rastreadores

Renderiza las etiquetas de rastreo con type="text/plain" y data-tc-consent. Las que se insertan en tiempo de ejecución desde hosts conocidos se retienen solas.

<script type="text/plain" data-tc-consent="analytics" async
        src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>
<script type="text/plain" data-tc-consent="analytics">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXX');
</script>

3. Registra consentimientos desde una action

Con una clave secreta, en el servidor. Cada decisión entra en la bóveda de solo anexión con un justificante firmado; consulta Registrar y consultar consentimiento.

// app/routes/signup.tsx — server side, with a secret key
import { CroombitClient } from '@croombit/sdk';
import type { Route } from './+types/signup';

const tc = new CroombitClient({ baseUrl: 'https://api.croombit.com', apiKey: process.env.CROOMBIT_SECRET_KEY! });

export async function action({ request }: Route.ActionArgs) {
  const form = await request.formData();
  const email = String(form.get('email'));
  // …create the account, then:
  await tc.recordConsent(
    { subject: 'email:' + email, purpose: 'newsletter', state: form.get('newsletter') ? 'GRANTED' : 'DENIED', channel: 'signup_form' },
    { idempotencyKey: crypto.randomUUID() },
  );
}

4. Un enlace "Configurar cookies"

<a href="#" data-tc-open-preferences>Configurar cookies</a>

Preguntas

¿Funciona en modo SPA?

Sí. Con ssr: false, el mismo Layout se prerenderiza en index.html, con la etiqueta incluida.

¿La hidratación ejecuta el script dos veces?

No. El navegador lo ejecuta una vez al leer el HTML del servidor; React hidrata el elemento sin volver a ejecutarlo.