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.

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.

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.
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
