Evita que Coralogix RUM robe tu red inicial

Coralogix RUM envía beacons durante la carga y roba red a tu propio LCP. Almacena los eventos en un buffer y envíalos al ocultar la página.

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-06-06

Evita que Coralogix RUM robe tu red inicial

Una herramienta de RUM tiene una sola tarea: medir la experiencia real de tus usuarios. Coralogix hace lo contrario durante la carga. Comienza a enviar beacons en cuanto llamas a init. Si esa llamada está en tu bundle principal, el SDK dispara su primer lote en la ventana de carga e hidratación, robando red al mismo LCP que debería estar midiendo. 

La herramienta primero empeora el número y luego lo reporta. Funciona al revés. Así que escribí una solución alternativa que almacena los datos en un buffer y los envía a la API de Coralogix al salir de la página (tal como hace Core/Dash por defecto, así que si buscas una herramienta de RUM mejor, considera cambiar).

Coralogix cree que es más importante que tu página

Mira contra qué compite ese beacon. Tu imagen principal. Tus fuentes. El script que hidrata la página. Con fibra óptica puede que nunca lo notes. Pero tus usuarios no están todos en fibra. En un teléfono, en un tren, con el wifi de un hotel, el ancho de banda escasea, y ese beacon compite con tu propio contenido por él. Los visitantes con las peores conexiones sí lo notarán. ¿Y para qué?

Y aquí está la parte que debería molestarte: no hay ninguna razón para enviar todos esos datos iniciales. Ninguna. Los datos son solo sobre una visita que aún está ocurriendo. Nadie los está leyendo en directo (y si lo hacen, sería bastante inquietante). Pueden quedarse en memoria y enviarse cuando termine la visita: no cuesta nada y no se pierde nada. Enviarlos durante la carga es todo desventajas. Solo puede ralentizar la página y no te aporta nada. Es absurdo. Así que recupera el control: captura cada evento, no envíes ninguno hasta que termine la visita.

corelogix network and main thread

Bien, basta de quejas. Hora de solucionarlo. ¡Así es como haces que Coralogix se comporte correctamente!

Almacena todo, no envíes nada

Coralogix te ofrece el hook beforeSend. Devuelve el evento y se enviará. Devuelve null y se descartará. Así que primero inserta el evento en un array y luego devuelve null. Cada evento capturado, nada en la red.

import { CoralogixRum } from '@coralogix/browser';

const PUBLIC_KEY = '<YOUR_PUBLIC_KEY>';
const APPLICATION = 'my-app';

// Captura cada evento, no envíes ninguno en tiempo real.
const buffer = [];

CoralogixRum.init({
  public_key: PUBLIC_KEY,
  application: APPLICATION,
  version: '1.0.0',
  coralogixDomain: 'EU1',
  beforeSend: (event) => {
    buffer.push({ event, t: Date.now() }); // registra la marca de tiempo ahora, envíalos más tarde
    return null;                           // suprime el beacon del propio SDK
  },
});

Comprobé que esto captura lo que importa, porque en la documentación beforeSend parece un filtro exclusivo para errores. No lo es. Se ejecuta para cada tipo de evento: la captura inicial (snapshot), los tiempos de recursos, cada Core Web Vital, las interacciones de usuario y los errores. El SDK sigue haciendo su trabajo real: medir toda la página. Solo se mantiene callado en la red hasta que le indiques que vacíe el buffer.

Vacíalo al salir

Ahora envía el buffer cuando la página se oculte. Aquí es donde falla la versión ingenua. Intentas usar navigator.sendBeacon, porque es la forma clásica de enviar en el unload. Aquí no funciona. El ingress se autentica con una cabecera Authorization: Bearer, y sendBeacon no permite configurar cabeceras de petición. Devuelve true y da un error 403 en silencio. Usa fetch con keepalive en su lugar. Sobrevive a la salida (unload) de la misma manera y te permite configurar la cabecera.

Otra cosa que el beacon te ocultó: el ingress no acepta eventos en bruto. El SDK envuelve cada uno en un span y hace un POST con { logs: [...] }. Así que reconstruye esa estructura antes de enviar.

const INGRESS = 'https://ingress.eu1.rum-ingress-coralogix.com/browser/v1beta/logs';
// cambia eu1 por tu región (us1, us2, eu2, ap1...) para que coincida con coralogixDomain

// El ingress espera la estructura del span del SDK, no los eventos en bruto. Reconstrúyela.
function toCxSpan({ event, t }) {
  const hasStack = !!(event.error_context
    && event.error_context.original_stacktrace
    && event.error_context.original_stacktrace.length);

  return {
    version_metadata: event.version_metadata,
    applicationName: APPLICATION,
    subsystemName: 'cx_rum',
    severity: (event.event_context && event.event_context.severity) || 3,
    isErrorWithStacktrace: hasStack,
    timestamp: t,
    text: { cx_rum: Object.assign({}, event, { timestamp: t }) },
  };
}

function flush() {
  if (!buffer.length) return;
  const logs = buffer.splice(0).map(toCxSpan); // vacía el buffer: una segunda llamada no enviará nada

  fetch(INGRESS, {
    method: 'POST',
    keepalive: true, // sobrevive al unload y, a diferencia de sendBeacon, permite establecer cabeceras
    headers: {
      'Authorization': 'Bearer ' + PUBLIC_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ logs, skip_enrichment_with_ip: false }),
  }).catch(function () {});
}

document.addEventListener('visibilitychange', function () {
  if (document.visibilityState === 'hidden') flush();
});
window.addEventListener('pagehide', flush);

splice vacía el buffer, por lo que un segundo evento de ocultación no enviará nada. visibilitychange a hidden es la señal fiable, incluso en dispositivos móviles donde unload nunca se activa. pagehide sirve como respaldo. Una advertencia: keepalive comparte un límite de 64 KB entre todas las peticiones en vuelo, por lo que una sesión larga que almacene miles de registros de recursos puede desbordarlo. Si recopilas muchos datos, divide el array logs en varios envíos más pequeños.

El coste

¡Ahora estás reconstruyendo el formato de Coralogix a mano, ten cuidado! El session_context es un poco más limitado que el del propio SDK. Coralogix completa el session id, user agent y device después de que se ejecute beforeSend, por lo que tus spans creados a mano tendrán menos detalles que un beacon normal. Para capturar las Core Web Vitals no importa. Para analítica profunda de sesiones podría importar. Y confirma que obtienes un código 200 en la pestaña Network en tu primer despliegue, porque una clave incorrecta o una regla CORS más estricta fallará de la misma forma silenciosa en que lo hacía el beacon.

Si mantener un formato de transferencia que no controlas te parece un dolor de cabeza, la alternativa más simple es posponer CoralogixRum.init() hasta después de la hidratación y dejar que el SDK envíe los datos con normalidad desde ahí. Perderás las métricas de carga previas a la inicialización, pero conservarás tu salud mental. Elige qué prefieres sacrificar.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

Escribo código, no informes.

Entro en tu equipo uno o dos sprints. Dejo montado el monitoring para que las métricas sigan verdes cuando me vaya.

Escríbeme
Evita que Coralogix RUM robe tu red inicialCore Web Vitals Evita que Coralogix RUM robe tu red inicial