Do not call a slow proxy request “TLS”, “server time”, or a provider fault from one total. For one new, successful HTTP/1.1 GET, curl can give four cumulative timestamps. Subtract adjacent timestamps to make four non-overlapping observations, then compare controlled samples.

This guide is for an operator maintaining an authorized workflow. It isolates a single transfer; it does not measure application queueing, retry backoff, parsing, DNS work done before curl, or a whole user journey. It also does not prove which network or service caused a delay.

Collect a narrow, interpretable sample

Use a harmless destination you control or are permitted to test. Run each sample in its own curl process with one URL. Use one HTTP/1.1 GET, no upload, no redirects, no retries and no informational response. Confirm the saved response headers contain no informational response. Keep the client host, proxy endpoint, target, request headers, payload size, concurrency, region and session mode fixed within a comparison group. Connection reuse makes the timestamps describe a different situation.

# PROXY_CONFIG is local, permission-restricted and never committed.
# It contains only approved proxy endpoint/authentication settings.
curl -q --config "$PROXY_CONFIG" --http1.1 --max-redirs 0 --retry 0 --max-time 30 \
  --dump-header response.headers --output response.body --silent --show-error \
  --write-out '{"curl_exit":%{exitcode},"http_status":"%{response_code}","connect":%{time_connect},"pretransfer":%{time_pretransfer},"starttransfer":%{time_starttransfer},"total":%{time_total}}\n' \
  'https://test.example/health'

-q must be the first option so curl does not load a default curlrc. The local configuration must not add URLs, uploads, retries, redirects, write-out formats or other behavior that defeats this controlled command. --max-time 30 is only a test ceiling, not a product-speed target. Keep credentials out of process arguments, shell history and output. %{exitcode} requires curl 7.75.0 or newer. The three-character status is intentionally quoted so curl's 000 remains valid JSON. Capture the exit code, HTTP status, timestamps, curl version, timestamp, client region, proxy product/endpoint identifier with secrets removed, target class, test configuration and body byte count. Use a separate sample directory for every response.body/response.headers pair so later samples cannot overwrite evidence. Save and validate the body before setting content_valid:true; inspect headers for informational responses. Only that flag, a 2xx response, and curl exit 0 are eligible for breakdown. A timeout such as curl exit 28 stays a failure record with any raw timing curl emitted; raw values are preserved, not validated as a breakdown. Do not substitute zero for missing phases.

Turn cumulative moments into intervals

curl documents time_connect as time from start until the remote host or proxy connection completes, so it can include earlier work such as DNS and is not a pure TCP-only measure. time_pretransfer includes protocol-specific pre-transfer commands and negotiations; time_starttransfer reaches the first byte received, usually response headers; and time_total includes the full transfer. Those are cumulative, so report:

connect_ms       = connect * 1000
post_connect_setup_ms = (pretransfer - connect) * 1000
wait_first_byte  = (starttransfer - pretransfer) * 1000
after_first_byte = (total - starttransfer) * 1000

For [.08, .32, .62, .82] seconds, the four intervals are 80 / 240 / 300 / 200 ms. They add back to 820 ms without double-counting.

IntervalWhat it containsDo not label it
connectConnection completion to the remote host or proxy.Only “proxy latency” or only TCP quality.
post-connect setupProtocol setup after connect, including proxy CONNECT/TLS/other negotiation as applicable.Pure TLS time.
wait-first-byteEverything from transfer start to first byte: network and server work can both contribute.Pure server CPU time.
after-first-byteThe remaining response, including remaining headers and body delivery, affected by size, transport and client writing.A provider throughput guarantee.

Use the offline analyzer without sending traffic

Download the standard-library analyzer. Running it without a file prints only labelled synthetic data; it never opens a network connection.

python3 proxy-latency-breakdown.py --self-test
python3 proxy-latency-breakdown.py

For real records, use strict JSON. It rejects negative values, NaN, missing timestamps, non-monotonic moments, reused connections and redirects. It rejects duplicate IDs for traceability. Failed rows can retain raw curl times, but it will not manufacture intervals for them. The tool verifies your declaration, not the traffic: inspect saved headers for 1xx and preserve the command/configuration evidence.

{
  "scope": {"connection":"new","http_version":"1.1","method":"GET","follow_redirects":false,"retries":0,"upload":false,"allow_1xx":false},
  "observations": [
    {"id":"sample-17","curl_exit":0,"http_status":"200","content_valid":true,"connect":0.08,"pretransfer":0.32,"starttransfer":0.62,"total":0.82},
    {"id":"timeout-18","curl_exit":28,"http_status":"000","content_valid":false,"total":20.0}
  ]
}

Save the JSON example as observations.json. For your measurements, place each curl output object in observations, add a unique id and the body-check result content_valid, and declare the verified collection scope once. Keep the original raw record separately. Then run:

python3 proxy-latency-breakdown.py observations.json

The supplied synthetic cases deliberately isolate a longer setup interval [.08,1.52,1.82,2.02], wait interval [.08,.32,2.12,2.32], and after-first-byte interval [.08,.32,.62,2.42]. They are teaching inputs, not IPHTML measurements.

Run a controlled decision experiment

Observed repeated changeControlled next checkDecision boundary
Connect growsCompare the same target and proxy endpoint from a second approved client network.Keep application queue/retry clocks separate; one path cannot assign blame.
Post-connect setup growsVerify proxy scheme, authentication mode and a fresh connection; compare an allowed direct baseline only when appropriate.Do not call it TLS-only or change credentials without evidence.
Wait-first-byte growsHold URL, headers, body and concurrency fixed; inspect permitted target-side telemetry if available.It may include network and server work.
After-first-byte growsRecord response bytes and client read behavior; compare equal-size responses.Do not use a larger response as a proxy gateway benchmark.

Use enough comparable samples across meaningful time bands before changing a paid configuration. A single fast or slow request is evidence about that transfer only. For complete-job deadlines, failures and retry recovery, use the reliability scorecard; this article only separates one transfer. If a workload needs continuity across several requests, measure that separately with the proxy session acceptance guide; do not reuse one connection-timing result as a session guarantee.

Send a useful, redacted escalation record

Window / timezone: [actual start and end, with UTC offset]
Scope: new HTTP/1.1 GET; no redirect/retry/upload/1xx; curl version:
Target class and permission: [redacted category]
Proxy endpoint/product: [host or plan identifier, no credentials]
Group controls: client region, concurrency, headers, response bytes, session mode
Records: id, curl exit, HTTP status, connect/post-connect-setup/wait-first-byte/after-first-byte intervals
Comparison: baseline group and changed variable
Question: which documented configuration or next safe test distinguishes the observed interval?

Remove proxy passwords, cookies, authorization headers, personal data and sensitive URL parameters. If the evidence shows a configuration question for an authorized recurring task, review rotating proxy options and contact support with the record. Ask about the current plan and configuration; this guide makes no latency, availability, price or support-response promise.

Method note: source definitions were checked on October 12, 2026 against official curl documentation for CONNECT_TIME, PRETRANSFER_TIME, STARTTRANSFER_TIME, TOTAL_TIME, and write-out. The offline tool was self-tested; no paid proxy or IPHTML performance test was run.