Next.js

Componente Script, estrategia correcta y CSP.

Growth Lab es una etiqueta de terceros, así que en Next.js se instala como cualquier script externo: con el componente Script y la estrategia correcta.

App Router

Añádelo al layout raíz, dentro de <body>:

// app/layout.tsx
import Script from 'next/script';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="es">
      <body>
        {children}
        <Script
          src="https://cdn.growthlab.ecomlabs.dev/sdk/v1/bootstrap.js"
          data-site-id={process.env.NEXT_PUBLIC_GROWTHLAB_SITE_ID}
          strategy="afterInteractive"
        />
      </body>
    </html>
  );
}

NEXT_PUBLIC_GROWTHLAB_SITE_ID puede ir en el código directamente: el site id es público por diseño. Usar una variable solo sirve para tener entornos distintos (producción y staging) sin tocar el código.

Pages Router

// pages/_app.tsx
import Script from 'next/script';

export default function App({ Component, pageProps }) {
  return (
    <>
      <Component {...pageProps} />
      <Script
        src="https://cdn.growthlab.ecomlabs.dev/sdk/v1/bootstrap.js"
        data-site-id={process.env.NEXT_PUBLIC_GROWTHLAB_SITE_ID}
        strategy="afterInteractive"
      />
    </>
  );
}

Qué estrategia usar

Estrategia Resultado
afterInteractive Recomendada. Carga en cuanto la página es interactiva.
beforeInteractive Solo si aceptas bloquear la hidratación. Reduce el parpadeo al mínimo a costa de LCP.
lazyOnload No la uses: el SDK cargaría después del primer render y la variante se vería aplicarse.

Con afterInteractive el anti-flicker del SDK sigue funcionando: oculta solo los elementos que la variante va a modificar, nunca la página entera, y los revela pasados 1,5 segundos aunque la configuración no haya llegado.

Content Security Policy

Si tu aplicación envía una CSP, añade los orígenes de Growth Lab:

script-src 'self' https://cdn.growthlab.ecomlabs.dev;
connect-src 'self' https://events.growthlab.ecomlabs.dev https://sessions.growthlab.ecomlabs.dev;

Sin connect-src el navegador bloquea el envío de eventos en silencio y el panel mostrará la instalación como pending para siempre.

Navegación por cliente

El App Router navega sin recargar. El SDK detecta el cambio de ruta con history y MutationObserver y vuelve a resolver los experimentos en cada URL, así que no hace falta llamar a nada manualmente.

Un visitante no cambia de variante al navegar: la asignación es determinística sobre su identificador y la clave del experimento.

Registrar una conversión

'use client';

export function CheckoutButton({ total }: { total: number }) {
  return (
    <button
      onClick={() => {
        window.GrowthLab?.conversion('purchase', { revenue: total, currency: 'MXN' });
      }}
    >
      Pagar
    </button>
  );
}

Consulta Conversiones y revenue para la deduplicación por identificador de pedido, que es lo que impide contar dos veces una compra si el usuario recarga la página de gracias.