Stop Coralogix RUM From Stealing Your Early Network
Coralogix RUM beacons during load and steals network from your own LCP. Buffer the events and flush them on page hide instead.

Stop Coralogix RUM from stealing your early network
A RUM tool has one job: measure the experience your users actually get. Coralogix does the opposite during load. It starts beaconing the moment you call init, so if that call sits in your main bundle the SDK fires its first batch into the load and hydration window and steals network from the very LCP it is meant to be measuring.
The tool first hurts the number, then reports it. That is backwards. So I write a workaround that buffers the data and sends it to the Coralogix API on page leave (just like Core/Dash does by default so if you are looking for a better RUM tool consider switching).
Coralogix thinks it is more important than your page
Look at what that beacon is competing with. Your hero image. Your fonts. The script that hydrates the page. On fiber you might never notice it. But your users are not all on fiber. On a phone, on a train, on hotel wifi, bandwidth is scarce, and that beacon fights your own content for it. The visitors on the worst connections they will notice it. Ant for what??
And here is the part that should bother you: there is no reason for it all that early data. None. The data is just about a visit that is still happening. Nobody is reading it live (and if they are that would be really creepy). It can sit in memory and go when the visit ends, cost nothing, and lose nothing. Sending it during load is all downside. It can only slow the page, and it buys you nothing. That is stupid. So take back the power: capture every event, send none of them until the visit is over.

Alright, enough ranting. Time to fix. This is how you make coralogix behave correctly!
Buffer everything, send nothing
Coralogix gives you a beforeSend hook. Return the event and it sends. Return null and it drops. So push the event into an array first, then return null. Every event captured, nothing on the wire.
import { CoralogixRum } from '@coralogix/browser';
const PUBLIC_KEY = '<YOUR_PUBLIC_KEY>';
const APPLICATION = 'my-app';
// Capture every event, send none of them live.
const buffer = [];
CoralogixRum.init({
public_key: PUBLIC_KEY,
application: APPLICATION,
version: '1.0.0',
coralogixDomain: 'EU1',
beforeSend: (event) => {
buffer.push({ event, t: Date.now() }); // stamp now, flush later
return null; // suppress the SDK's own beacon
},
}); I checked that this catches what matters, because beforeSend reads like an error-only filter in the docs. It is not. It fires for every event type: the init snapshot, resource timing, every web vital, user interactions, and errors. The SDK keeps doing its real job, measuring the whole page. It just goes quiet on the network until you tell it to flush.
Flush it on the way out
Now send the buffer when the page is hidden. This is where the naive version dies. You reach for navigator.sendBeacon, because that is the textbook way to send on unload. It does not work here. The ingress authenticates with an Authorization: Bearer header, and sendBeacon cannot set request headers. It returns true and 403s in silence. Use fetch with keepalive instead. It survives unload the same way, and it lets you set the header.
One more thing the beacon hid from you: the ingress does not take raw events. The SDK wraps each one in a span and posts { logs: [...] }. So rebuild that shape before you send.
const INGRESS = 'https://ingress.eu1.rum-ingress-coralogix.com/browser/v1beta/logs';
// swap eu1 for your region (us1, us2, eu2, ap1...) to match coralogixDomain
// The ingress wants the SDK's span shape, not raw events. Rebuild it.
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); // drain: a second call sends nothing
fetch(INGRESS, {
method: 'POST',
keepalive: true, // survives unload, and unlike sendBeacon it can set headers
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 drains the buffer, so a second hidden event sends nothing. visibilitychange to hidden is the reliable signal, even on mobile where unload never fires. pagehide is the backstop. One caveat: keepalive shares a 64KB budget across in-flight requests, so a long session that buffers thousands of resource entries can overflow it. If you collect heavily, chunk the logs array into a few smaller posts.
What it costs
You are now rebuilding Coralogix's format by hand, be carefull! The session_context is a bit thinner than the SDK's own. Coralogix fills in the session id, user agent, and device after beforeSend runs, so your hand-built spans carry less of that detail than a normal beacon would. For Core Web Vitals capture it does not matter. For deep session analytics it might. And confirm a 200 in your Network tab on first deploy, because a wrong key or a tightened CORS rule fails the same silent way the beacon did.
If maintaining a wire format you do not own sounds like a bad time, the blunt alternative is to defer CoralogixRum.init() until after hydration and let the SDK send normally from there. You lose the pre-init loading metrics, but you keep your sanity. Pick your trade.
Find out what is actually slow.
I map your critical rendering path using real field data. You get a prioritized fix list, not a Lighthouse report.
Get the audit
