v158 · performance · resource timing

Resource timing: get encoded/decoded body size with CORS instead of TAO

A PerformanceResourceTiming entry reports three byte counts — encodedBodySize, decodedBodySize, transferSize — but for cross-origin resources they are gated. Historically the gate was the Timing-Allow-Origin header. Chrome 158 changes which gate applies: body sizes are facts about the content, not the fetch, so they follow the CORS opt-in that already guards responseStatus and contentType — while transferSize, which mixes content and network detail, now requires both CORS and TAO.

concepts

  1. Body size basics

    Fetch this site's own assets and read the three byte counts off the real PerformanceResourceTiming entry, delivered live by a PerformanceObserver: compression ratio from encoded vs decoded, cache hits from transferSize === 0, and header overhead from transfer minus encoded. Same-origin, so every field is always exposed — the baseline the gates subtract from.

  2. The gate matrix

    Five real fetches — same-origin, CORS+TAO, TAO-only (opaque), CORS-only, and neither — against public endpoints whose headers are documented in-page. Two of the rows disagree between the old TAO rule and the new CORS rule, so the matrix doesn't just explain the change: it detects which regime the browser you are using right now actually implements, and says so.

  3. Third-party weight audit

    The practical stakes: a RUM-style auditor that fetches any third-party URL you give it and reports exactly which byte counts your analytics could see for it, in this browser, plus which response header — Access-Control-Allow-Origin or Timing-Allow-Origin — the resource's owner would need to add under the old and new rules to unlock the rest.

why it shipped

The resource-timing group concluded years ago (issue #220) that Timing-Allow-Origin should opt a resource into timing — and body sizes say more about a response's content than about the process of fetching it. The CORS-protected attributes added since (responseStatus, contentType, contentEncoding) already follow that logic. Chrome 158 brings encodedBodySize and decodedBodySize into line: exposed for cross-origin resources fetched with CORS, no longer unlocked by TAO alone. transferSize straddles the line — bytes on the wire are both content and network — so it requires both opt-ins. Firefox and Safari signalled support; WebKit today is stricter still, exposing body sizes only same-origin.

the API

const res = await fetch("https://cdn.example/lib.js");       // mode: "cors"
await res.blob();                                             // finish the body

const [entry] = performance.getEntriesByName(res.url).slice(-1);
entry.decodedBodySize;  // bytes after decompression
entry.encodedBodySize;  // bytes before decompression (as transferred body)
entry.transferSize;     // body + ~header estimate; 0 for cache hits & when gated

// Gating for CROSS-ORIGIN resources:
//           pre-158 Chrome        Chrome 158+
// encoded/decodedBodySize:  TAO   ->  CORS (response not opaque)
// transferSize:             TAO   ->  CORS *and* TAO

references