Guide
How to Test Proxy Latency: A Repeatable Method
Learn how to test proxy latency with repeatable checks for connection time, TTFB, routing, and location performance before you scale automation workloads.

Testing proxy latency correctly requires separating the components of the total request time and measuring each one in isolation. Most naive latency tests measure everything at once — gateway connection, proxy routing, and target response — and attribute the result to the proxy. This produces misleading comparisons because target response time dominates and varies independently of the proxy. A repeatable method gives you numbers you can trust and reproduce.
What You Are Actually Measuring
A proxied request involves several distinct time segments:
DNS resolution: Resolving the proxy gateway hostname (usually cached after the first request, negligible in ongoing tests).
TCP handshake to gateway: The round-trip time to establish a TCP connection with the proxy gateway. Primarily a function of geographic distance between your test machine and the gateway.
CONNECT tunnel setup (for HTTPS): The additional round-trip for the proxy to establish a TCP connection to the target server and confirm the tunnel is ready.
TLS handshake: The time to negotiate TLS with the target server through the proxy tunnel.
Time to first byte (TTFB): The time from when the HTTP request was sent until the first byte of the response body arrives. This includes target server processing time.
Full response transfer: Time to receive the complete response.
For proxy performance evaluation, the most relevant measurements are the TCP handshake to gateway and the CONNECT tunnel setup — these are the proxy-specific contributions. TTFB includes target processing time and is useful for end-to-end benchmarking but should not be interpreted as proxy latency alone.
Setting Up a Latency Test
Choose a neutral, fast target
Your test target should have negligible server-side processing time so that TTFB reflects routing overhead rather than backend computation. Good choices:
- A static file on a CDN endpoint with known fast response times
- An IP lookup endpoint that returns a small JSON response
- Your own lightweight test server in a known location
Avoid dynamic pages, heavy sites, or any target with variable server-side processing. The goal is to isolate proxy overhead, not test the target.
Use a tool that reports timing components separately
curl with the --write-out flag reports the full timing breakdown:
curl --proxy "http://user:pass@proxy.provider.com:8080" \
--write-out "%{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total}\n" \
--output /dev/null \
--silent \
https://your-test-target.com/small-fileThis outputs six timing values in seconds:
time_namelookup: DNS resolutiontime_connect: TCP handshake complete (to the gateway)time_appconnect: TLS negotiation complete (through the proxy to target)time_pretransfer: Request senttime_starttransfer: First byte received (TTFB)time_total: Full response received
The proxy-specific contribution is approximately time_appconnect - time_namelookup. The target contribution is approximately time_starttransfer - time_appconnect.
Run enough samples
A single measurement is noise. The residential proxy IP routing through a consumer device adds variance that a single sample does not capture. Run a minimum of 50 requests per configuration and measure p50, p90, and p99 — not just the average.
for i in $(seq 1 50); do
curl --proxy "http://user:pass@proxy.provider.com:8080" \
--write-out "%{time_appconnect}\n" \
--output /dev/null \
--silent \
https://your-test-target.com/small-file
done | sort -n | awk '
{data[NR]=$1}
END {
n=NR
print "p50:", data[int(n*0.50)]
print "p90:", data[int(n*0.90)]
print "p99:", data[int(n*0.99)]
}
'Test at your target concurrency
Single-threaded latency does not predict concurrent latency. At high concurrency, gateway and pool resource contention can increase latency significantly. Test at the concurrency level you plan to operate at, not just serially.
A Python async test that exercises 20 concurrent connections:
import asyncio
import time
import httpx
PROXY = "http://user:pass@proxy.provider.com:8080"
TARGET = "https://your-test-target.com/small-file"
CONCURRENCY = 20
TOTAL_REQUESTS = 200
async def single_request(client, results):
start = time.perf_counter()
try:
r = await client.get(TARGET)
elapsed = time.perf_counter() - start
results.append(("ok", elapsed))
except Exception as e:
elapsed = time.perf_counter() - start
results.append(("err", elapsed))
async def run_benchmark():
results = []
semaphore = asyncio.Semaphore(CONCURRENCY)
async def bounded_request(client):
async with semaphore:
await single_request(client, results)
async with httpx.AsyncClient(proxy=PROXY, timeout=30) as client:
tasks = [bounded_request(client) for _ in range(TOTAL_REQUESTS)]
await asyncio.gather(*tasks)
ok = [t for s, t in results if s == "ok"]
ok.sort()
n = len(ok)
print(f"Completed: {n}/{TOTAL_REQUESTS}")
print(f"p50: {ok[int(n*0.50)]:.3f}s")
print(f"p90: {ok[int(n*0.90)]:.3f}s")
print(f"p99: {ok[int(n*0.99)]:.3f}s")
asyncio.run(run_benchmark())Testing Geographic Routing
If you use city-level targeting, test whether the IP geolocation is accurate and whether IPs in different cities show different routing characteristics.
For each target city:
- Request a proxy IP with city-level targeting
- Confirm the IP geolocates to the correct city via a neutral lookup
- Run the latency benchmark
- Record p50/p90/p99 for that city's IP pool
Cities served by geographically distributed IP pools with nearby gateway routing will show lower TTFB when accessing targets in the same region. This is relevant for use cases where the data you are collecting is location-specific and you care about both accuracy and speed.
Comparing Proxy Types
When evaluating multiple proxy types or providers, hold everything constant except the proxy configuration:
- Same test target
- Same test machine location
- Same number of samples
- Same concurrency level
- Same time of day (pool utilization varies by time)
Record results in a table:
| Proxy type | p50 (ms) | p90 (ms) | p99 (ms) | Error rate |
|---|---|---|---|---|
| Datacenter | 38 | 52 | 71 | 0.5% |
| Rotating residential | 180 | 420 | 1,240 | 1.2% |
| ISP dedicated | 55 | 89 | 143 | 0.3% |
The p99 difference between proxy types is often larger than the p50 difference. For operations running at high concurrency over long periods, the tail latency matters more than the median — slow p99 requests tie up threads and limit effective throughput.
What Latency Numbers Mean in Practice
A 200ms p50 TTFB through a residential proxy on a fast target means your collection job produces roughly 5 requests per second per thread at that latency. At 50 concurrent threads, that is 250 requests per second maximum throughput — ignoring retry overhead and target-side rate limiting.
For throughput planning, use p90 rather than p50 as your estimate, since a meaningful fraction of requests will be slower than the median. Use p99 to size your timeout thresholds so that the vast majority of requests complete before you declare them failed.
FlameProxies provides residential, ISP, and datacenter proxy access from a single gateway endpoint, making it straightforward to run the comparison above and route each job to the proxy type that best fits its latency requirements.