Defining TTFB

Time to First Byte (TTFB) measures the duration from the start of a page navigation until the first byte of the response begins to arrive. It represents the sum of several request phases:

  • Redirect time
  • Service worker startup time (if applicable)
  • DNS lookup
  • Connection and TLS negotiation
  • Request time up to the arrival of the first response byte

Lowering TTFB generally requires reducing latency in connection setup and improving backend response times.

TTFB and Early Hints

The introduction of 103 Early Hints has raised questions about what counts as the "first byte." A 103 Early Hints response does count as the first byte for TTFB purposes. The finalResponseHeadersStart timing entry complements responseStart by measuring the start of the final document response (typically an HTTP 200).

Early Hints is one example of a broader pattern: some servers flush parts of the response—such as HTTP headers or the <head> element—before the full body is ready. These early responses all land under responseStart and therefore affect TTFB. Sending data early is valuable when the complete response will take time, but it complicates cross-platform TTFB comparisons because measurement depends on the features and technologies in use. The key is understanding what your measurement tool captures and how the platform being tested influences it.

Interpreting TTFB scores

Since TTFB precedes user-centric metrics like First Contentful Paint (FCP) and Largest Contentful Paint (LCP), servers should respond to navigation requests quickly enough that the 75th percentile of users achieve an FCP within the "good" threshold. As a general guideline, most sites should aim for a TTFB of 0.8 seconds or less.

Measuring TTFB

TTFB can be assessed in both lab and field settings using various tools.

Field measurement

Lab measurement

JavaScript measurement for navigation requests

For navigation requests, the Navigation Timing API provides the necessary data. The example below creates a PerformanceObserver that logs navigation entries:

new PerformanceObserver((entryList) => {
  const [pageNav] = entryList.getEntriesByType('navigation');

  console.log(`TTFB: ${pageNav.responseStart}`);
}).observe({
  type: 'navigation',
  buffered: true
});

The web-vitals library offers a more concise approach:

import {onTTFB} from 'web-vitals';

// Measure and log TTFB as soon as it's available.
onTTFB(console.log);

Measuring resource request TTFB

TTFB applies to all requests, not only navigations. Cross-origin resources are particularly relevant since establishing connections to additional servers introduces latency. The Resource Timing API within a PerformanceObserver handles this measurement:

new PerformanceObserver((entryList) => {
  const entries = entryList.getEntries();

  for (const entry of entries) {
    // Some resources may have a responseStart value of 0, due
    // to the resource being cached, or a cross-origin resource
    // being served without a Timing-Allow-Origin header set.
    if (entry.responseStart > 0) {
      console.log(`TTFB: ${entry.responseStart}`, entry.name);
    }
  }
}).observe({
  type: 'resource',
  buffered: true
});

This snippet resembles the navigation example but queries for 'resource' entries instead of 'navigation'. It also accommodates same-origin resources that may report 0 because the connection is already established or the resource is served from cache.

Improving TTFB

For strategies to reduce your site's TTFB, consult the optimizing TTFB guide.