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.
| Phase label | Formula | What the interval contains |
|---|---|---|
| Lookup | time_namelookup | The lookup cURL performed, often the proxy endpoint on a proxied path |
| TCP | time_connect - time_namelookup | TCP setup to the remote host or proxy |
| Negotiation | time_pretransfer - time_connect | Protocol-specific work before transfer, which can include proxy and TLS negotiation |
| First-byte wait | time_starttransfer - time_pretransfer | Request transit, intermediary behavior, edge or cache work, and server processing combined |
| Body | time_total - time_starttransfer | The remainder of the completed transfer |
- 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.
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
# 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
| Lane | Control | Question |
|---|---|---|
| Direct, cold | Fresh direct connection | What does setup plus transfer look like without the configured proxy? |
| Proxy, cold | Fresh proxied connection | What changed when gateway and tunnel setup entered the path? |
| Direct, warm | Deliberate connection reuse | How much setup disappears on the direct path? |
| Proxy, warm | Deliberate connection reuse | How much setup disappears on the proxied path? |
- 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.
- Network
Main request starts
DNS, connection, proxy negotiation, TLS, request transit, and response transfer happen here.
- Response
Headers and main body arrive
The main document can finish while other page work remains outstanding.
- Lifecycle
DOMContentLoaded and load fire later
Parsing, scripts, styles, frames, and subresources can extend navigation beyond the main response.
- 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.