Reference guide · performance · Published 2026-08-16 · 3 min read

Resource Timing API for site-speed analysis

Use the Resource Timing API to get real DNS, connect, TLS, TTFB and transfer-size timing for every asset and find what slows a page.

The Resource Timing API is the browser's built-in answer to a simple question: how long did every asset on the page actually take to load? Lighthouse and page-speed tools give you totals, but this API gives you the per-file breakdown, in real field conditions, for the users who actually visit. Its data underpins the network waterfall and request timing shown in browser DevTools, and you can collect it in JavaScript for your own monitoring.

What it gives you

Every resource the page fetches, from images and scripts to stylesheets and font files, produces a PerformanceResourceTiming entry in the browser's performance buffer. Each entry exposes a full loading timeline as high-resolution timestamps, plus the size of the resource and the type of element that requested it.

Because each entry carries fractional-millisecond timestamps for DNS lookup, TCP connection, TLS negotiation, first byte of response, and full transfer, you can attribute delay to the right layer. A page can feel slow because of a slow DNS lookup, a cold TLS handshake, an origin that responds slowly, or simply assets that are too big, and the API tells you which one is true for each file.

A privacy rule matters when you read results: for resources loaded from another origin, the timing fields such as domainLookupStart, connectStart and responseStart are reported as zero unless that origin sends a Timing-Allow-Origin header. Only the size fields and final completion time remain useful for those cross-origin assets without that header.

The key timestamps

The most useful fields are the differences between pairs of timestamps in the entry:

Two more properties are worth reading directly. initiatorType tells you what caused the fetch, such as img, script, link or css. renderBlockingStatus tells you whether a stylesheet or script blocked the render of the page, which is exactly the signal you want when shortening first paint.

Using it in code

You can read all entries right after load, or filter them for a single asset.

performance.getEntriesByType("resource").forEach((r) => {
  const ttfb = r.responseStart - r.requestStart;
  if (ttfb > 300) {
    console.log(`${r.name}: TTFB ${Math.round(ttfb)}ms, ${r.transferSize} bytes`);
  }
});

For raw timing on the main document itself, use the navigation entry, which you can fetch with performance.getEntriesByType("navigation"). It exposes the same fields plus the full page-load mark, making it the natural companion for comparing page start to first byte.

The most reliable workflow is to buffer entries throughout a visit or page life cycle via a PerformanceObserver, batch them into your monitoring or analytics payload, and use the slowest assets as the short list for optimisation. Because the data comes from real users, it captures exactly the network conditions DevTools and synthetic tests hide. See how to read a request waterfall for the visual counterpart, and improve TTFB for turning a high responseStart delay into a fix.

Need a website built, fixed, optimised, migrated or replaced?

This technical resource is written by CSMBAC, a small design and development studio. If you would rather hand the problem to a professional, the website service page explains how we build enquiry-ready websites.

Explore website services