Why naive speed tests mislead
Running a single online speed test through a proxy tells you very little. Proxy speed depends on the path between you and the proxy, the proxy and the target, the exit node's own connection, and the target's response time. A meaningful test measures the right components, from the right place, against the right target, many times.
What to measure
| Metric | What it tells you |
|---|---|
| Connect time | Latency to the proxy gateway |
| TLS handshake time | Latency through the tunnel to the target |
| Time to first byte (TTFB) | How quickly the target starts responding via the proxy |
| Total time | End-to-end request duration |
| Throughput | Download speed for large responses |
| Success rate | Requests that completed correctly |
| p50 / p95 / p99 | Typical and worst-case performance |
Tail latency (p95/p99) matters: timeouts come from the slow tail, not the median.
Where to test from
Test from where you'll run in production: your scraping server, your sneaker bot VPS, or your office. Testing from a laptop on home Wi-Fi when production runs in a data centre gives misleading numbers. See sneaker bot server location.
What to test against
Your real target, or at least a target hosted in the same region and on similar infrastructure. Testing against a nearby CDN-hosted site measures something different from your actual workload.
curl timing
curl -s -o /dev/null -x http://USER:PASS@gate.example.com:7777 \
-w 'dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total} size:%{size_download}\n' \
https://www.example.com/Run it many times and look at the distribution. See curl proxy.
Python benchmark
import time, statistics, requests
from concurrent.futures import ThreadPoolExecutor
def timed(proxy, url):
t = time.perf_counter()
try:
r = requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=30)
return time.perf_counter() - t, r.status_code == 200
except requests.RequestException:
return time.perf_counter() - t, False
def bench(proxy, url, n=200, workers=10):
with ThreadPoolExecutor(workers) as ex:
res = list(ex.map(lambda _: timed(proxy, url), range(n)))
ok = sorted(t for t, s in res if s)
return {
"success": len(ok) / n,
"p50": round(statistics.median(ok), 3) if ok else None,
"p95": round(ok[int(len(ok) * 0.95) - 1], 3) if ok else None,
}Interpreting results by proxy type
| Type | Typical profile |
|---|---|
| Datacenter | Lowest latency, tight distribution |
| ISP | Low latency, consistent |
| Residential | Higher median, wider tail |
| Mobile | Variable, depends on signal and carrier |
A residential pool with a higher median but excellent success may beat a fast datacenter pool that's blocked. Always read speed alongside success rate. See residential vs datacenter proxies.
Improving proxy speed
- Choose a gateway close to your server.
- Choose exit locations close to your target.
- Use ISP or datacenter where trust requirements allow.
- Reuse connections within sticky sessions.
- Drop consistently slow exits.
- Keep your own server uncongested.
Proxy tip: When troubleshooting, it helps to have a second, known-good proxy to compare against. A small pay-as-you-go balance from Geonode works well for that, and its dashboard shows usage and active sticky sessions. More in using Geonode in your browser.
Benchmarking multiple providers fairly
| Rule | Why |
|---|---|
| Same server | Removes your network as a variable |
| Same time window | Residential pools vary by hour |
| Same targets | Different sites respond differently |
| Same concurrency | Load affects latency |
| Same number of requests | Comparable statistics |
| Same targeting | Country/city affects exit distance |
Visualising results
Plotting latency distributions (histograms or box plots) per provider makes differences obvious: one provider may have a lower median but a long tail of slow requests that cause timeouts. Even a simple sorted list of p50/p90/p95/p99 per provider is informative.
Throughput tests
For bandwidth-heavy tasks, test download throughput with a large file:
curl -s -o /dev/null -x http://USER:PASS@gate.example.com:7777 \
-w 'speed: %{speed_download} bytes/s total: %{time_total}s\n' \
https://speed.example.com/100MB.binUse a test file hosted near your target region. Residential throughput depends heavily on the exit's home connection.
Speed vs cost trade-offs
| Faster option | Cost implication |
|---|---|
| ISP instead of residential | Per-IP pricing; often cheaper for heavy use |
| Datacenter instead of residential | Much cheaper, if not blocked |
| Closer gateway | Usually free to choose |
| City-level targeting near target | May cost more and shrink pool |
See proxy pricing guide and cheap proxies.
A quick five-minute speed check
If you just need a quick sense of a proxy's speed:
- From your production server, run the curl timing command 20 times against your target.
- Note the median and worst
time_starttransfer. - Repeat without a proxy (if allowed) to see the overhead the proxy adds.
- Repeat with a second provider or location for comparison.
for i in $(seq 1 20); do
curl -s -o /dev/null -x http://USER:PASS@gate.example.com:7777 -w '%{time_starttransfer}\n' https://www.example.com/
done | sort -n | awk '{a[NR]=$1} END {print "median", a[int(NR/2)], "max", a[NR]}'What "fast enough" means by use case
| Use case | What matters |
|---|---|
| Bulk scraping | Throughput and p95; individual request speed matters less |
| Browser automation | Page load time; p95 to avoid timeouts |
| Sneaker checkouts | Latency to the specific retailer |
| Account management | Consistency more than raw speed |
| Gaming | Ping and jitter (often better without a proxy) |
See sneaker proxy speed and best proxies for gaming.
Reporting results so others can trust them
Speed numbers get passed around teams and forums stripped of context, and then nobody can reproduce them. When you publish or share a result, include:
| Item | Example |
|---|---|
| Date and time window | 14 to 16 October 2026, 09:00 to 21:00 UTC |
| Test location | VPS in Frankfurt, 2 vCPU |
| Proxy product and targeting | Rotating residential, country DE, sticky 10 minutes |
| Target | Your own test server, or a named public page |
| Sample size | 2,000 requests per provider |
| Success definition | 200 status and expected content |
| Metrics | Success rate, p50, p95, throughput |
| What failures counted as | Excluded from latency, included in success rate |
A result written up this way can be repeated next month or by a colleague, which is the only way to tell whether a provider has really got faster or slower.
Two habits help further: always report a percentile alongside any average, and never compare numbers measured from different servers or at different times of day. For logging every timing in a machine-readable way, see the %{json} tip in curl proxy. For turning results into a buying decision, see how to test proxies before buying, and for the monthly uptime side, proxy provider support and SLAs.
Key takeaways
- Measure connect time, TLS time, TTFB, total time, throughput, success and tail latency (p95/p99).
- Test from your production server, against your real target, with realistic concurrency.
- Compare providers under identical conditions and at the same time of day.
- Read speed alongside success rate; a fast blocked proxy is worthless.
- Choose closer gateways and exits, and the fastest proxy type your target accepts. See how to test proxies before buying.
FAQ
What's a good proxy response time?
It depends on the target and type. Compare providers against each other on the same test.
Why is my proxy fast in tests but slow in my scraper?
Different target, different concurrency, or your scraper's own overhead (parsing, rendering).
Does more concurrency slow proxies down?
Beyond a point, yes, both at the provider and on your side. Test at your real concurrency.
Editorial note: Proxy providers change their pools, features and prices often, so treat any figures here as typical ranges at the time of writing and confirm current terms with the provider before you buy.