v158 · resource timing · rum practice
Third-party weight audit
The question every RUM dashboard eventually asks: how many bytes is that third-party script costing my users? Whether your analytics can answer depends entirely on the response headers the third party sends — and on which gating rule the visitor's browser applies. This auditor fetches any URL you give it and reports what a measurement tool running on this page could actually see, plus the exact header that would unlock the rest.
All fetches happen from your browser, live. A cross-origin URL fetched with mode: "cors" only succeeds if the resource sends Access-Control-Allow-Origin; the auditor falls back to an opaque no-cors fetch when CORS is refused, exactly as a script tag without crossorigin would load it. Failures are reported as failures. From Chrome 158 the body-size gate is CORS (ResourceTimingUseCORSForBodySizes, no chrome://flags entry on older builds — only --enable-blink-features=…).
Audit a resource
Any https URL. It is fetched from your browser only; nothing is sent anywhere else.
- fetched as
- —
- decodedBodySize
- —
- encodedBodySize
- —
- transferSize
- —
- responseStatus
- —
- duration
- —
What this means for your RUM data
the practical rules of thumb
If you control the third party's headers (or can file a ticket with the vendor): Access-Control-Allow-Origin (plus loading with crossorigin) is what unlocks body sizes from Chrome 158 on, and it already unlocks responseStatus, contentType and contentEncoding everywhere those shipped. Timing-Allow-Origin remains the opt-in for the detailed timing breakdown (DNS, connect, TTFB) — and from 158 it is also still required, together with CORS, for transferSize. A vendor that sends both, like the CDN preset above, gives your telemetry the full picture in every browser generation; a vendor that sends neither is a byte-count black hole, and no client-side trick changes that — by design.
code path
// Audit as a RUM library would: prefer CORS (full visibility from 158),
// fall back to the opaque load a plain <script src> would produce.
let res, mode = "cors";
try {
res = await fetch(url, { mode: "cors", cache: "no-store" });
} catch {
mode = "no-cors";
res = await fetch(url, { mode: "no-cors", cache: "no-store" }); // opaque
}
await res.blob();
const entry = performance.getEntriesByName(url).at(-1);
// entry.decodedBodySize / encodedBodySize / transferSize — 0 means "gated"