Saltar a contenido

Analítica de eventos con Zaraz

Qué mide el storefront, dónde se consulta cada evento y qué hay que saber antes de sacar conclusiones de los números. Corresponde a la HU-03.

Este documento tiene dos destinatarios: quien analiza los datos (las secciones 1 a 5) y quien toca el código (las secciones 6 y 7).


1. Los tres lugares donde mirar

Dónde Para qué sirve Cuándo usarlo
Debugger de Zaraz (panel de Cloudflare) Ver los eventos en vivo mientras se navega, con todos sus parámetros Verificar que algo se dispara, y con qué valores
Jitsu El evento completo, tal como se guarda Contar, sumar y cruzar. Es la fuente confiable
GA4 Los informes armados Reportes habituales, con las salvedades del punto 3.2

Empezar siempre por el debugger de Zaraz para confirmar que el evento sale, y recién después buscarlo en Jitsu o GA4.


2. Qué se mide

Trece eventos, todos verificados en vivo el 2026-09-10.

El recorrido de compra

Evento Se dispara cuando Desde qué pantalla
Product List Viewed Se muestra una lista de productos Tienda, categorías, home, relacionados
Product Clicked Se hace clic en un producto de una lista Todas las grillas
Product Viewed Se abre la ficha de un producto Ficha
Products Searched Se ejecuta una búsqueda Tienda con ?q=
Product Added Se agrega al carrito Ficha y carrito
Product Removed Se saca del carrito Carrito y desplegable del header
Cart Viewed Se abre la página del carrito Carrito

El checkout

Los seis viajan con el mismo checkout_id, que es el id del carrito. Es lo que permite medir en qué paso se cae la gente.

Evento Se dispara cuando
Checkout Started Se entra al checkout con productos
Checkout Step Viewed Se abre cada paso (1 Dirección, 2 Envío, 3 Pago, 4 Revisión)
Checkout Step Completed Se avanza desde un paso al siguiente
Shipping Info Entered Se confirma el método de envío y se avanza
Payment Info Entered Se confirma el método de pago y se avanza
Order Completed Se confirma la compra

El paso 4 no emite Checkout Step Completed: completar la revisión es comprar, y eso lo reporta Order Completed. Contarlo dos veces inflaría la conversión.


3. Avisos que hay que leer antes de sacar conclusiones

Esta sección es la más importante del documento. Todo lo que sigue fue medido, no supuesto.

3.1. quantity significa dos cosas distintas

  • En Product Viewed y en las listas, quantity es la disponibilidad: 1 si el producto se puede comprar, 0 si está agotado. Se usó ese campo porque la lista de parámetros de Zaraz no tiene ninguno de stock.
  • En Product Added, Product Removed, Cart Viewed y Order Completed, quantity son unidades reales.

Consecuencia: no se pueden sumar los quantity de todos los eventos juntos. Hay que filtrar por evento primero.

Además, value no multiplica por quantity cuando éste es la bandera de stock. Si lo hiciera, todo lo agotado valdría 0 y hundiría el valor por sesión.

3.2. En GA4 el cero cambia de tipo de parámetro

Zaraz manda los números distintos de cero como epn. (numérico) y el cero como ep. (texto). Medido: ep.num_cero=0 junto a epn.num_uno=1.

Consecuencia: un mismo campo (quantity, nb_hits) cae en dimensión de texto cuando vale 0 y en métrica cuando no. Para sumar o promediar esos campos hay que usar Jitsu, no GA4.

3.3. El debugger muestra en blanco los valores 0 y false

No están perdidos: en el POST real a Jitsu llegan intactos. La tabla del debugger no los renderiza. Verificado mandando el mismo dato en nueve codificaciones.

Si un campo aparece vacío en el debugger, probablemente vale cero.

3.4. El debugger no lista los eventos en orden cronológico

Hay que ordenar por hora antes de concluir que algo falta. Por leer la lista de arriba abajo se dieron por perdidos cuatro eventos que sí habían llegado.

3.5. En el carrito se reporta la cantidad final, no la diferencia

Decisión del stakeholder (2026-09-09). Pasar de 1 a 5 unidades reporta Product Added con quantity: 5, no con 4.

Consecuencia aceptada: las unidades agregadas que sume el panel no coinciden con el carrito. Pasar por 2, 3 y 4 reporta 9 unidades para un carrito de 4. Para contar unidades vendidas hay que usar Order Completed, no la suma de Product Added.

La excepción es el botón de borrar, que reporta las unidades que tenía la línea.

3.6. Shipping Info Entered subcuenta

El botón "Ir a pagar" del carrito lleva al paso que corresponda según el estado del carrito. Un visitante que abandona el checkout y vuelve con el envío ya elegido entra directo en el paso de pago y nunca dispara ese evento, porque vive en el botón de "Continuar a pago" y no en la URL.

Consecuencia: ese escalón del embudo va a mostrar menos gente de la que realmente pasó por él.

3.7. El precio de las listas puede no coincidir con el de la venta

Product List Viewed y Product Clicked reportan el precio del índice de Algolia, que es el que la tarjeta muestra en pantalla. Cart Viewed, Checkout Started y Order Completed reportan el de Medusa, que es el que se cobra.

Mientras el índice esté desactualizado, los dos números difieren. Medido el 2026-09-10 con el sku CPI-673517: 1.399.000 en la lista, 1.607.141 cobrado.

No es un error de la medición — el evento reporta lo que el visitante vio — pero no se pueden comparar esos precios entre sí.

3.8. brand tiene cobertura incompleta

  • En los eventos que salen de Medusa (ficha, carrito, checkout, venta) la cobertura es de 83%.
  • En los que salen de Algolia (listas, clics) sale casi siempre vacío, porque el índice no trae la marca.

Consecuencia: un informe de "vistas por marca" sobre las listas va a estar muy incompleto. Usar los eventos de ficha en adelante.

3.9. Los ids pueden no cruzar mientras el índice esté viejo

El product_id es el id de variante. Un mismo sku puede tener distinto id de variante en Algolia y en Medusa mientras el índice esté desactualizado.

Mientras tanto, cruzar por sku, que sí coincide.

3.10. Quién es quién: cfz y user_id

  • cfz identifica el navegador. Viaja siempre, también sin sesión iniciada. Jitsu lo recibe como anonymousId. Es el mismo id que usa el enlace de WhatsApp, así que la conversación cruza con la navegación.
  • user_id identifica a la persona: es el id de cliente de Medusa, y sólo viaja cuando hay sesión iniciada.

Sin user_id, el mismo cliente que mira desde el celular y compra desde la computadora son dos visitantes distintos.


4. Los campos de producto

Todos los eventos con productos usan el mismo mapeo, para que el mismo producto se mida igual en toda la tienda.

Campo Qué es
product_id Id de variante, no del producto padre
name Título de la variante
sku De la variante
category Del producto
brand Del producto — ver 3.8
variant Valores de las opciones unidos con " - " (ej. "Rojo"), sin la marca
price Guaraníes enteros, con IVA incluido. No dividir por 100
quantity Ver 3.1
position Lugar en la lista, empezando en 1
value price × unidades reales

Si un dato no existe, la clave no se manda. Nunca llega vacía: un "" sería una fila (vacío) en los informes.

Un precio en 0 se omite, junto con currency y value. Un cero no es un precio barato, es un dato que el integrador no cargó, y hundiría el ticket promedio.

La position con paginación

Es la posición del listado completo, no la de la página: en la página 2 el primer producto es el 13. Si se reiniciara en cada página, el informe mostraría que lo más clickeado está siempre en las primeras posiciones — sería un artefacto del conteo.

No todas las grillas la mandan. Hoy la mandan la tienda, las categorías, la home y los relacionados; si el campo no está, es que esa grilla no la conoce.


5. Qué NO se mide

  • Order Updated, Order Refunded y Order Cancelled. Ocurren en el admin de Medusa, no en el navegador. Necesitan un suscriptor en el backend.
  • Los filtros del panel lateral. El panel de Zaraz tiene los triggers Clicked Filters y Viewed Filters creados, pero nadie los emite todavía.
  • Product Added to Wishlist, porque la wishlist se sacó del sitio, y Viewed Promotion / Clicked Promotion, excluidos a propósito.

Errores abiertos en el panel (no son del código)

  • La conversión "Search" de Google Ads sale con la búsqueda vacía (&label=&query=). El log de Zaraz lista {{ variable.bt-query }} entre los Empty values: la variable del panel no está tomando el query, que sí llega bien y que GA4 sí mapea a ep.search_term.

6. Dónde vive el código

Archivo Qué hace
src/lib/analytics/zaraz.ts Emisor. Tiene la cola y vincula cfz y user_id
src/lib/analytics/product-event.ts El único mapeo. Producto, línea de carrito, pedido y registro de Algolia
src/lib/util/product-attributes.ts Marca, categoría, opciones y stock. Compartido con el JSON-LD
src/modules/analytics/components/ Un componente por evento de pantalla

Regla que sostiene todo: un solo mapeo para todos los eventos. Si cada uno armara el suyo, el mismo producto llegaría distinto según por dónde pasó el visitante y el embudo no cerraría.

La cola de eventos

Cloudflare inyecta Zaraz después de que la página carga, así que los eventos que se disparan al abrir salían antes y se perdían. Medido: la primera tanda de Product List Viewed (posiciones 1 a 15) nunca llegaba.

Por eso emitirEvento() guarda en una cola lo que no puede enviar y lo manda cuando Zaraz aparece. Guarda hasta 30 eventos, sondea cada 300 ms y descarta a los 20 segundos, para el visitante con bloqueador donde Zaraz no va a aparecer nunca.

El despacho es del lado del servidor

Zaraz recibe el evento en el navegador pero lo despacha desde el worker de Cloudflare ("channel": "server"). Por eso se puede emitir justo antes de una navegación dura sin que se pierda.


7. Cómo depurar

En desarrollo la consola registra todos los eventos, lleguen o no a Zaraz. Buscar [zaraz] en la consola del navegador.

En un ambiente desplegado, agregar ?zarazdebug a la URL una vez. Queda guardado en localStorage y desde ahí la consola registra igual.

Sirve para separar dos casos que se parecen: si el evento aparece en la consola pero no en el debugger, el problema es del envío; si no aparece en la consola, el problema es del código.

Para probar el checkout

  • Sin productos en el carrito, /checkout devuelve "Página no encontrada", y no emite ningún evento. Es el comportamiento correcto, no un error.
  • Hay que recorrerlo con los botones. Pegar ?step=payment o ?step=review en la URL no dispara Shipping Info Entered ni Payment Info Entered: esos eventos viven en los manejadores de los botones, a propósito, para que no reporten datos que nadie ingresó.
  • Para repetir una prueba sin comprar de nuevo: desde Revisión, tocar Editar en Envío y volver a avanzar.

Para volver a emitir un Order Completed

Se deduplica por pedido en localStorage, porque esa página se recarga y se vuelve a abrir desde el correo. Para forzar una nueva emisión, borrar la clave zaraz_order_completed:<id del pedido>.