Resource Timing API: Measuring DNS, TCP, and TLS

The Resource Timing API enables web developers to collect granular, high-resolution network timing data for every resource fetched by a web page. By exposing specific timestamps for each step of the network lifecycle, this API allows engineers to isolate and measure individual connection setup phases, specifically Domain Name System (DNS) lookups, Transmission Control Protocol (TCP) handshakes, and Transport Layer Security (TLS) negotiations. Understanding how these metrics are captured and calculated is essential for identifying infrastructure bottlenecks and optimizing modern web performance.

Accessing Resource Timing Data

The Resource Timing API is accessible via the global performance object in modern browsers. Fetching resource performance records is typically done using:

const resources = performance.getEntriesByType('resource');

Each item returned is a PerformanceResourceTiming object, which inherits from PerformanceEntry. These objects contain timestamps recorded with microsecond precision (DOMHighResTimeStamp), representing milliseconds elapsed since the time origin (typically page navigation start).

Isolating the DNS Phase

Before a client can connect to an origin server, it must resolve the domain name into an IP address. The Resource Timing API captures this operation using two properties:

  • domainLookupStart: The timestamp immediately before the browser starts the domain name lookup.
  • domainLookupEnd: The timestamp immediately after the domain name lookup is complete.

To calculate the total DNS lookup duration:

const dnsDuration = resource.domainLookupEnd - resource.domainLookupStart;

If a persistent connection is reused or the domain is already cached by the browser, both values will often be identical to fetchStart, resulting in a duration of zero.

Isolating the TCP Handshake

Once the IP address is resolved, the browser establishes a TCP connection to the host. The connection phase is tracked by:

  • connectStart: The timestamp immediately before the browser starts establishing the connection to the server.
  • connectEnd: The timestamp immediately after the connection is established, including the completion of the TLS handshake (if HTTPS is used).

For unencrypted HTTP connections, the TCP handshake duration is calculated directly as:

const tcpDuration = resource.connectEnd - resource.connectStart;

Isolating the TLS Negotiation Phase

When establishing a secure HTTPS connection, the TLS negotiation occurs within the overall connection window. The API exposes this sub-phase using:

  • secureConnectionStart: The timestamp immediately before the browser initiates the TLS handshake.

Because TLS negotiation happens after the initial TCP three-way handshake, secureConnectionStart divides the overall connect window into two distinct segments:

  1. Pure TCP Handshake Time:

    const tcpDuration = resource.secureConnectionStart - resource.connectStart;
  2. TLS Negotiation Time:

    const tlsDuration = resource.connectEnd - resource.secureConnectionStart;

If HTTPS is not used, or if a persistent connection is reused (such as in HTTP/2 or HTTP/3 multiplexing), secureConnectionStart returns 0, indicating that no new cryptographic handshake was required.

The Timing-Allow-Origin Requirement

For security and privacy reasons, cross-origin resources do not expose these granular network phases by default; the timestamps will be reported as 0. To grant the consuming web page access to DNS, TCP, and TLS metrics for third-party assets (such as CDNs, fonts, or external scripts), the external server must send the following HTTP response header:

Timing-Allow-Origin: *

Or restrict it to specific origins:

Timing-Allow-Origin: https://yourdomain.com

With this header present, developers can accurately break down the initial connection phases across all site assets to pinpoint network latency issues effectively.