Testing a proxy's speed is free and takes one command. The harder part is knowing which number you measured and whether it describes the route your job will actually use. This guide covers both. The curl timers with their exact meanings, a small Python version for a loop, and the two rules that keep a latency figure honest.
"Speed" is really three numbers, and most searches look for one of them without naming the proxy at all. "Time to first byte" draws far more interest than any proxy-speed phrase, which is a hint about what to measure.
How do you test proxy speed?
Route a request through the proxy with curl and print its timing variables. This one line gives the two numbers that matter most, the connect time and the total time, without downloading a byte of the page body:
curl -x http://IP:PORT -o /dev/null -s -w "connect:%{time_connect} total:%{time_total}\n" https://example.com
-x sets the proxy, -o /dev/null throws away the body, -s silences the progress bar, and -w prints the timers after the request finishes. Every number is in seconds. Run it a handful of times before you trust it.
Are latency, throughput and TTFB the same number?
No. People say "speed" and mean one of three things. Measuring the wrong one is how a proxy looks fine in a test and fails in production.
- Latency is round-trip time: send a request, count the milliseconds until an answer comes back. It is set mostly by physical distance, because signals in fiber travel at a finite speed, so a proxy on the far side of the planet is slow no matter how fast its hardware is. Latency is what matters for many small requests, where the per-request overhead dominates.
- Throughput is bandwidth: once the connection is open, how many bytes per second it moves. curl's documentation defines
speed_downloadas exactly this, "the average download speed that curl measured for the complete download. Bytes per second." It is what matters for pulling large pages, files or media. - Time to first byte is the gap between finishing your request and the first byte of the response arriving. MDN defines it as the time between the request and the first byte of the response. curl reports it as
time_starttransfer, and the curl manual adds that this figure "includes the time the server needed to calculate the result". That is what makes it the best "is this proxy responsive" signal.
A proxy can be low-latency and low-throughput, or the reverse. So a real test reports both, and reads TTFB to tell a sluggish proxy from a sluggish target.
How do I time a proxy with curl, stage by stage?
curl exposes the whole request lifecycle through -w (or --write-out), documented in the curl manual. Asking for each stage shows where the time goes:
curl -x http://IP:PORT -o /dev/null -s \
-w "dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n" \
https://example.com
Each variable is a cumulative stopwatch from the start of the request, so the differences between them are what you read. The meanings are curl's own.
curl's timing variables, in curl's own words
| Variable | What curl says it measures |
|---|---|
| time_namelookup | Until the name resolving was completed |
| time_connect | Until the TCP connect to the remote host (or proxy) was completed |
| time_appconnect | Until the SSL/SSH/etc connect/handshake to the remote host was completed |
| time_starttransfer | Until the first byte was received, including the time the server needed to calculate the result (this is the TTFB) |
| time_total | The total time that the full operation lasted |
| speed_download | The average download speed curl measured, in bytes per second |
curl --write-out documentation, read October 23, 2026
DNS lookup
time_namelookup
TCP connect
time_connect, to the proxy
TLS handshake
time_appconnect
First byte
time_starttransfer, the TTFB
Transfer done
time_total
If time_connect is high, the hop to the proxy is slow or the proxy is overloaded. If time_starttransfer is much larger than time_connect, the proxy connected and then took its time producing a response. That is the classic signature of a tired free proxy. To measure throughput instead of latency, download something with a known size and read the speed meter:
curl -x http://IP:PORT -o /dev/null -s -w "%{speed_download} bytes/s\n" https://your-target.example/largefile.bin
What do those timers look like on a known case?
To show the timers against numbers we control, we built two tiny servers on our own machine, no real proxy and no real site. A local origin waits 300 milliseconds before its first byte, then streams 2,000,000 bytes. A minimal local proxy sits in front of it. Then we ran the stage-by-stage command above through them.
The reading matches the design and shows what each timer means. time_connect is about one millisecond, the cost of reaching the proxy next door. time_starttransfer is about 0.33 seconds, close to the 300 ms the origin was told to wait, because TTFB folds in the server's think time. time_total is larger again, since the throttled 2 MB body still had to arrive, and speed_download reports that body's average rate. On a real proxy to a real site the same five numbers separate the hop, the wait and the transfer the same way.
Can I time it in Python instead?
Yes, which is the better choice when you test many proxies in a loop. The clean way is time.perf_counter around a single call:
import time
import requests
proxies = {"http": "http://203.0.113.7:8080", "https": "http://203.0.113.7:8080"}
start = time.perf_counter()
r = requests.get("https://example.com", proxies=proxies, timeout=(5, 30))
elapsed_ms = (time.perf_counter() - start) * 1000
print(f"status {r.status_code} {elapsed_ms:.0f} ms {len(r.content)} bytes")
One reading is noise. On a shared proxy the honest number is the median of several. That drops the occasional stall without letting one lucky sample flatter a bad proxy:
import statistics
import time
import requests
proxies = {"http": "http://203.0.113.7:8080", "https": "http://203.0.113.7:8080"}
samples = []
for _ in range(10):
t = time.perf_counter()
requests.get("https://example.com", proxies=proxies, timeout=(5, 30))
samples.append((time.perf_counter() - t) * 1000)
print(f"median {statistics.median(samples):.0f} ms best {min(samples):.0f} ms")
requests also hands you a TTFB-like figure without any stopwatch. r.elapsed is a timedelta from sending the request to finishing the response headers, and r.elapsed.total_seconds() is often all the latency signal you need. For the wider picture in Python, our Python requests guide covers sessions, rotation and the timeout handling these loops depend on.
Why must I test from the region that matters?
Because a latency number is only meaningful next to the route it measured, and this is where most home-grown tests go wrong. From your laptop, the figure includes your own hop to the proxy, a hop your production server in another data center may not share. A proxy that answers a nearby test URL in 80 ms can still be slow to the distant site you actually scrape. The proxy-to-target leg is part of the real cost.
Two rules keep the numbers honest. First, test from the same region your job will run in, so the client-to-proxy leg matches production. Second, test against a target near where you will really send traffic, not just example.com, so the proxy-to-target leg is realistic. This also explains a routine surprise. A mobile proxy usually tests slower and more variable than a datacenter IP, because the cellular leg genuinely adds latency. That is the price of the trust it buys. The same distance logic makes persistent slowness on a nearby target a red flag, one chased in how to fix a 504 gateway timeout.
Is there a faster way than scripting?
Timing one proxy by hand is quick. Grading a batch is tedious. "Good" means fast and exiting where you expect and still anonymous, and stitching those checks into a script is a chore. Our proxy checker runs the whole battery on a paste: the exit IP, latency, real exit country and anonymity grade, with no signup. It runs from our own infrastructure rather than your laptop, so your local connection does not skew the latency figure. That makes it the fastest way to sort a handful of candidates. It pairs with the liveness walkthrough in how to check if a proxy is working.
Whichever method you use: measure right before the proxy goes to work, take the median of several samples, and judge the number against the route. For latency that stays low and predictable, our residential proxies cost $0.50/GB for one GB, falling to $0.44/GB at 2,000 GB+. You can also practice these commands on a few entries from our free proxy list, which drops the dead instead of counting them.
What we could not check
- The console figure is a local-stub measurement. It demonstrates what the curl timers mean against values we chose, and it says nothing about any real proxy's speed, because we test nothing on our network or anyone's.
- Latency depends on the route, so every "good number" on this page is a rule of thumb for one distance rather than a promise.
- curl adds and renames write-out variables between releases. This page is due for a check by January 23, 2027.
Sources and further reading
- curl, the
--write-outdocumentation and the curl manual, read October 23, 2026: the definitions oftime_connect,time_starttransfer,time_totalandspeed_download. - MDN Web Docs, Time to first byte (TTFB): the definition of TTFB and where it sits in the request lifecycle.
- Google Keyword Planner, worldwide monthly searches, read October 23, 2026.



