Proxy Latency, Origin Latency, or Browser Timeout? How to Measure the Difference

A Playwright timeout is a deadline crossing. Split the request into phases before assigning the delay to a proxy, an origin, or the browser.

Open the timing worksheet

A 30-second Playwright timeout does not mean the proxy added 30 seconds. It means the operation missed a configured deadline. The main document may not have connected, may still be transferring, or may have finished while the browser waited for a later lifecycle event. The error alone cannot choose among those cases.

A deadline tells you when the client stopped waiting. Timings tell you where the wait accumulated.

Turn cumulative cURL clocks into phases

The cURL write-out fields (opens in a new tab) are cumulative from the start of the transfer. Subtract adjacent boundaries to get useful intervals. With an explicit proxy, time_connect ends when TCP connects to the remote host or proxy, so the labels describe the path cURL actually opened.

A practical phase worksheet for one cURL row
Phase labelFormulaWhat the interval contains
Lookuptime_namelookupThe lookup cURL performed, often the proxy endpoint on a proxied path
TCPtime_connect - time_namelookupTCP setup to the remote host or proxy
Negotiationtime_pretransfer - time_connectProtocol-specific work before transfer, which can include proxy and TLS negotiation
First-byte waittime_starttransfer - time_pretransferRequest transit, intermediary behavior, edge or cache work, and server processing combined
Bodytime_total - time_starttransferThe remainder of the completed transfer
A practical phase worksheet for one cURL row
Phase label
Lookup
Formula
time_namelookup
What the interval contains
The lookup cURL performed, often the proxy endpoint on a proxied path
Phase label
TCP
Formula
time_connect - time_namelookup
What the interval contains
TCP setup to the remote host or proxy
Phase label
Negotiation
Formula
time_pretransfer - time_connect
What the interval contains
Protocol-specific work before transfer, which can include proxy and TLS negotiation
Phase label
First-byte wait
Formula
time_starttransfer - time_pretransfer
What the interval contains
Request transit, intermediary behavior, edge or cache work, and server processing combined
Phase label
Body
Formula
time_total - time_starttransfer
What the interval contains
The remainder of the completed transfer

The first-byte interval is not pure origin compute. A proxy exit can change the network route, cache state, edge location, and origin behavior. Direct minus proxied is only the observed path difference for those matched samples.

Decompose one request, locally.

Paste cURL's cumulative timing values. The worksheet subtracts adjacent clocks so you can see where the recorded time accumulated.

cURL cumulative seconds

Enter the raw seconds as printed. Each value must be at least the value before it.

Browser comparison Optional

Insufficient evidence. 5 cumulative cURL values are still missing.

Insufficient evidence

Enter all five cumulative cURL values before drawing a timing picture.

Nothing leaves this page. Inputs are calculated in your browser and are not saved, logged, or sent anywhere.

Capture one comparable row

Write a phase row without printing credentials
LOCAL ONLY
# Apply your normal proxy configuration locally. Keep secrets out of this file.
curl --silent --show-error --output /dev/null \
  --write-out $'%{time_namelookup},%{time_connect},%{time_pretransfer},%{time_starttransfer},%{time_total},%{http_connect},%{num_connects},%{num_redirects},%{response_code},%{size_download},%{proxy_used}\n' \
  "$TARGET_URL"

Record status, CONNECT code, proxy_used, num_connects, redirects, response bytes, exit geography, and whether the connection was cold or warm beside every timing row. Without those fields, two numbers that look comparable may describe different routes or reuse states.

Compare four lanes, not one stopwatch

The four lanes answer different questions
LaneControlQuestion
Direct, coldFresh direct connectionWhat does setup plus transfer look like without the configured proxy?
Proxy, coldFresh proxied connectionWhat changed when gateway and tunnel setup entered the path?
Direct, warmDeliberate connection reuseHow much setup disappears on the direct path?
Proxy, warmDeliberate connection reuseHow much setup disappears on the proxied path?
The four lanes answer different questions
Lane
Direct, cold
Control
Fresh direct connection
Question
What does setup plus transfer look like without the configured proxy?
Lane
Proxy, cold
Control
Fresh proxied connection
Question
What changed when gateway and tunnel setup entered the path?
Lane
Direct, warm
Control
Deliberate connection reuse
Question
How much setup disappears on the direct path?
Lane
Proxy, warm
Control
Deliberate connection reuse
Question
How much setup disappears on the proxied path?

Alternate direct and proxied trials instead of running one entire group first. Hold URL, method, body, headers, target fixture, exit geography, and time window constant. Preserve every sample and report the sample count plus a median and tail. One run is an anecdote, and an average alone can hide the failures that matter.

Keep main-document time separate from navigation time

Playwright's request.timing() (opens in a new tab) exposes DNS, connection, secure-connection, request, and response boundaries for an individual request. Some fields can be -1 when unavailable, and responseEnd becomes available when that request finishes. Treat -1 as missing, never as zero.

  1. Network

    Main request starts

    DNS, connection, proxy negotiation, TLS, request transit, and response transfer happen here.

  2. Response

    Headers and main body arrive

    The main document can finish while other page work remains outstanding.

  3. Lifecycle

    DOMContentLoaded and load fire later

    Parsing, scripts, styles, frames, and subresources can extend navigation beyond the main response.

  4. Harness

    The chosen wait condition settles or expires

    The deadline belongs to the operation you configured, not to one network phase.

By default, page.goto() waits for load (opens in a new tab). Its documentation discourages networkidle as a readiness signal. Compare commit, DOMContentLoaded, load, and your application assertion only as separate observations. A main response that repeatedly finishes well before navigation settlement makes lifecycle, subresource, or harness work a candidate for the remaining gap.

Use server timing only when you control the evidence

An authorized origin can expose backend or cache measurements through Server-Timing (opens in a new tab). Those values are supplied by the server and may require same-origin access or Timing-Allow-Origin for browser visibility. Treat them as optional corroboration, not a universal source of truth.

What to record on the next failure

  • the exact client deadline, wait condition, actual elapsed time, and whether any HTTP response was observed;
  • the five cURL boundaries or available Playwright timing fields, with missing values left missing;
  • CONNECT code, response status, normalized client error, redirects, response bytes, and connection reuse;
  • direct or proxied lane, cold or warm state, proxy endpoint alias, and exit geography;
  • main-response completion, DOMContentLoaded, load, and application assertion as separate timestamps; and
  • optional Server-Timing values from an owned or authorized origin.

Use the status hub when the failure includes a response or client error, the four-cell diagnostic when the clients disagree, and the session recorder when the exit identity drifts. Apply the same evidence standard from the methodology and responsible-use policy.

From the field notes

Continue this diagnostic.

Carry the same standard into provider research

Compare the evidence currently available for each proxy, then inspect the rules behind every public result.