Time to First Byte (TTFB)

Browser Support

  • 43
  • 12
  • 31
  • 11

Source

Time to First Byte (TTFB) is a foundational metric for measuring connection setup time and web server responsiveness in both the lab and the field. It measures the time between the request for a resource and when the first byte of a response begins to arrive. This makes it helpful in identifying when a web server is too slow to respond to requests. In the case of navigation requests—that is, requests for an HTML document—it precedes every other meaningful loading performance metric.

A diagram of network request timings. The phases from left to right are Redirect (which overlaps with Prompt for Unload), Cache, DNS, TCP, Request, Response, Processing, and Load. The associated timings are redirectStart and redirectEnd (which overlap with the Prompt for Unload's unloadEventStart and unloadEventEnd), fetchStart, domainLookupStart, domainLookupEnd, connectStart, secureConnectionStart, connectEnd, requestStart, responseStart, responseEnd, domInteractive, domContentLoadedEventStart, domContentLoadedEventEnd, domComplete, loadEventStart, and loadEventEnd.
A diagram of network request phases and their associated timings. TTFB measures the elapsed time between startTime and responseStart.

TTFB is the sum of the following request phases:

  • Redirect time
  • Service worker startup time (if applicable)
  • DNS lookup
  • Connection and TLS negotiation
  • Request, until the first byte of the response arrives

Reducing latency in connection setup time and on the backend helps lower your TTFB.

What is a good TTFB score?

Because TTFB happens before user-centric metrics such as First Contentful Paint (FCP) and Largest Contentful Paint (LCP), we recommend that your server respond to navigation requests quickly enough so that the 75th percentile of users experience an FCP within the "good" threshold. As a rough guide, most sites should strive to have a TTFB of 0.8 seconds or less.

Good TTFB values are 0.8 seconds or less, poor values are greater than 1.8 seconds, and anything in between needs improvement
Good TTFB values are 0.8 seconds or less, and poor values are greater than 1.8 seconds.

Key point: Because TTFB isn't a Core Web Vitals metric, it's not absolutely necessary for sites to have an excellent TTFB, as long as the longer TTFB doesn't make it harder for your site to score well on the metrics that matter. When optimizing load times, consider how your site delivers content. A low TTFB is especially important if a site delivers its initial markup quickly and then has to wait for scripts to populate it with meaningful content, as is often the case with Single Page Applications (SPAs). On the other hand, a server-rendered site that doesn't require much client-side work can have better FCP and LCP values than a client-rendered site, even if its TTFB is higher.

How to measure TTFB

TTFB can be measured in the lab or in the field in the following ways.

Field tools

Lab tools

Measure TTFB in JavaScript

You can measure the TTFB of navigation requests in the browser using the Navigation Timing API. The following example shows how to create a PerformanceObserver that listens for a navigation entry and logs it to the console:

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

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

The web-vitals JavaScript library can also measure TTFB in the browser with less complexity:

import {onTTFB} from 'web-vitals';

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

Measure resource requests

TTFB applies to all requests, not just navigation requests. In particular, resources hosted on cross-origin servers can introduce latency while setting up connections to those servers. To measure TTFB for resources in the field, use the Resource Timing API in a PerformanceObserver:

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

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

The preceding code snippet is similar to the one used to measure the TTFB for a navigation request, except that instead of querying for 'navigation' entries, you query for 'resource' entries instead. It also accounts for the fact that some resources loaded from the primary origin might return a value of 0 if the connection is already open, or a resource is instantaneously retrieved from a cache.

How to improve TTFB

For guidance on improving your site's TTFB, see our in-depth guide to optimizing TTFB.