A/B testing en Next.js y React sin parpadeo
Cómo evaluar variantes en el servidor con Next.js o Remix, hidratar sin perder la asignación y medir conversiones en una SPA.
En una aplicación React el problema no es asignar la variante: es hacerlo antes del primer pintado. Si el HTML llega con el diseño A y el cliente cambia a B al hidratar, el visitante ve un salto y las métricas se ensucian.
Las dos formas de hacerlo
| Enfoque | Ventaja | Coste |
|---|---|---|
| Cliente (snippet + hooks) | Instalación de una línea, sirve para cualquier stack | Necesita anti-flicker para ocultar el salto |
| Servidor (SSR) | Sin parpadeo ni ocultación: el HTML ya sale con la variante | Requiere evaluar la variante en cada request |
En Next.js con App Router, lo natural es el segundo.
Evaluar la variante en el servidor
// app/page.tsx
import { createFluxABServer } from '@fluxab/sdk/server';
import { cookies } from 'next/headers';
const fluxab = createFluxABServer({ projectKey: process.env.FLUXAB_KEY! });
export default async function Page() {
const visitorId = (await cookies()).get('fluxab_vid')?.value ?? crypto.randomUUID();
const { variant } = await fluxab.getVariant('home-hero', { visitorId });
return variant === 'B' ? <HeroB /> : <HeroA />;
}
El cálculo es determinista por visitorId, así que el HTML del servidor y el del cliente coinciden y la hidratación no rompe nada.
Guardar el visitor id
El visitorId debe sobrevivir a la navegación y al paso al cliente:
// middleware.ts
import { NextResponse } from 'next/server';
export function middleware(req: Request) {
const res = NextResponse.next();
if (!req.headers.get('cookie')?.includes('fluxab_vid=')) {
res.cookies.set('fluxab_vid', crypto.randomUUID(), { maxAge: 60 * 60 * 24 * 365 });
}
return res;
}
Con la cookie puesta en el middleware, el servidor y el navegador usan el mismo identificador.
Pasar la variante al cliente
Cuando necesites la variante en componentes de cliente (hooks, eventos), pásala como prop desde el servidor. FluxABProvider expone useVariant / useTrack para el resto del árbol:
// app/providers.tsx
'use client';
import { FluxABProvider } from '@fluxab/sdk/react';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<FluxABProvider projectKey={process.env.NEXT_PUBLIC_FLUXAB_KEY!}>
{children}
</FluxABProvider>
);
}
Medir conversiones
Una SPA no recarga la página. El SDK envía un $pageview por ruta la primera vez que la ve, así que después de un cambio de ruta con pushState/replaceState solo tienes que llamar a refresh():
fluxAB.refresh();
Para conversiones de negocio, usa eventos explícitos:
'use client';
import { useTrack } from '@fluxab/sdk/react';
export function BuyButton() {
const track = useTrack();
return (
<button onClick={() => { track('begin_checkout', { plan: 'pro' }); openCheckout(); }}>
Empezar
</button>
);
}
Si ya emites a GA4, recuerda configurar el Measurement ID en el proyecto: el servidor reenviará cada conversión con experiment y variant.
Probar que funciona
- Abre la página con
?fluxab_force=Bpara ver la variante sin registrar datos. - Revisa que el HTML del servidor (ver código fuente) contiene la variante.
- Comprueba en el panel del proyecto que aparecen asignaciones del dominio verificado.
- Con dos pestañas y el mismo
visitorId, la variante debe coincidir siempre.
Antes de producción, verifica el dominio en el panel del proyecto: sin verificación, el SDK carga pero no registra datos.
Errores comunes
- Evaluar la variante en el cliente y en el servidor con IDs distintos: siempre el mismo
visitorId. - Cachear el HTML con la variante dentro: si usas ISR o CDN, marca la respuesta como
no-storeo segmenta por cookie; si no, todos los visitantes ven la misma variante. - Duplicar el snippet: en Next.js no instales el script global y el provider.
- Trackear en
useEffectsin deduplicar: el doble render de React en desarrollo puede enviar dos eventos.
Tienes la referencia completa del SDK (navegador, React y servidor) en la documentación.
¿Quieres aplicar esto con datos reales?
El plan gratuito de fluxAB incluye editor visual, mapas de calor y 5.000 visitantes al mes, sin tarjeta.
Crear cuenta gratis