Solución de problemas
El snippet no reporta, la variante no aplica, CORS.
Diagnóstico de los problemas que aparecen en la práctica, en orden de frecuencia.
El snippet está puesto pero la verificación dice pending
La verificación consulta si el colector recibió eventos, no si la etiqueta existe. Si dice pending:
- Abre la consola del navegador en tu sitio. ¿Hay errores de red hacia
events.growthlab.ecomlabs.dev? - Comprueba tu CSP. Necesitas
script-srcpara el CDN yconnect-srcpara el colector. - Comprueba si un bloqueador está filtrando la petición. Prueba en una ventana privada sin extensiones.
- Confirma que
data-site-idcoincide exactamente con el del panel.
En la consola:
window.__GL_STATE__; // undefined = el SDK no cargó
Si existe, revisa window.__GL_STATE__.errors.
Dice wrong_domain
El snippet funciona, pero los eventos llegan de un host que no registraste. Añade ese dominio en Sitios → Configuración → Dominios permitidos.
El colector rechaza orígenes no registrados porque el site-id es público: sin esa comprobación, cualquiera podría ponerlo en su página y contaminar tus datos.
Los subdominios del dominio principal se aceptan automáticamente. evilTienda.com no coincide con tienda.com.
La variante no se aplica
Mira window.__GL_STATE__.errors. Los códigos relevantes:
| Código | Causa | Solución |
|---|---|---|
variant_unapplied |
Ningún selector alcanzó la confianza mínima | El elemento cambió; reeditá la variante |
change_failed |
Un cambio concreto falló | Revisa ese selector |
apply_threw |
El JS personalizado lanzó | Corrige el JS de la variante |
config_fetch_failed |
No se pudo descargar la configuración | Revisa CSP y red |
module_load_failed |
No cargó experiments.js |
Revisa CSP y red |
no_collect_endpoint |
Configuración sin endpoints | Reporta el incidente |
variant_unapplied es deliberado
Si ningún candidato supera el umbral de confianza, el SDK no aplica nada y revierte al control.
Aplicar un cambio al elemento equivocado es mucho peor que no aplicarlo: corrompe los datos del experimento en silencio, mientras que no aplicarlo es visible y se reporta.
Ocurre normalmente tras un cambio de tema. Vuelve a seleccionar el elemento en el editor visual para regenerar los selectores.
Veo un parpadeo del contenido original
El SDK oculta solo los elementos que la variante va a modificar, con un límite de 1.5 s tras el cual los revela pase lo que pase.
Para reducirlo:
- Pon la etiqueta lo más arriba posible del
<head>. - No la cargues por gestor de etiquetas si el parpadeo te importa: GTM añade su propia latencia.
- No uses
defer.asyncestá bien.
Growth Lab no oculta <body> entero. Esa técnica hace que el sitio parezca roto durante cada descarga lenta, y si el SDK falla la página queda en blanco indefinidamente.
Un visitante cambió de variante
Solo debería ocurrir si:
- Subiste la versión del experimento. Eso reasigna a propósito.
- Rotaste la sal de asignación del sitio.
- El visitante perdió a la vez la cookie y el
localStorage(navegador nuevo, modo privado, limpieza completa).
Ampliar la asignación de tráfico no reasigna: inclusión y variante usan espacios de hash distintos precisamente para eso.
Errores de CORS
Los colectores aceptan cualquier origen, así que un error de CORS suele significar otra cosa:
- La petición se bloqueó antes de salir (CSP, bloqueador).
- Estás llamando a la API (
api.growthlab...) desde el navegador de tu sitio. La API mantiene lista blanca estricta porque maneja credenciales; el SDK no debe llamarla.
Recibo 429
Rate limit. Límites por defecto:
| Superficie | Límite |
|---|---|
| Colector de eventos | 6.000 req/min por IP |
| Colector de sesiones | 300 req/min por IP |
| API autenticada | 300 req/min por IP |
| Login por correo | 10 / 5 min |
Un 429 en el colector durante una prueba de carga desde una sola máquina es el comportamiento correcto, no un fallo.
Las conversiones se cuentan doble
Envía orderId:
GrowthLab.conversion('purchase', { value: 129900, currency: 'MXN', orderId: '1042' });
Sin él, una recarga de la página de agradecimiento cuenta otra compra.
El revenue sale ~100 veces menor
Estás enviando decimales. value va en unidades mínimas: 2999, no 29.99. Convierte con Math.round(valor * 100).
Los resultados dicen insufficient_data con números que parecen claros
Faltan condiciones. Mira decision.blockers:
| Bloqueador | Qué falta |
|---|---|
min_sample_not_reached |
Visitantes por variante |
min_duration_not_reached |
Días de ejecución (por defecto 7) |
probability_below_threshold |
Confianza posterior |
expected_loss_too_high |
Riesgo aceptable |
guardrail_breach |
El revenue por visitante cae |
srm_detected |
El reparto de tráfico está roto |
12% contra 3% con 100 visitantes parece enorme y no es evidencia. La duración mínima existe porque quien compra en lunes no es quien compra en sábado.
srm_detected
El reparto observado no coincide con el configurado a un nivel que no explica el azar. Todas las métricas del experimento son sospechosas.
Causas habituales: un redirect que pierde visitantes, un bloqueador que afecta a una variante más que a otra, o exposición registrada antes de aplicar los cambios.
No interpretes los resultados hasta resolverlo.
Nada funciona y necesito parar ya
Sitios → Configuración → Kill switch. Detiene todos los experimentos del sitio en ≤60 s y revierte los cambios aplicados sin recargar. Se comprueba antes que cualquier otra cosa, incluso antes de una variante forzada por preview.