๐ŸŽ‰ Premium Proxies ยท 24-Hour Free TrialClaim Now
Proxy Basic

Proxy Latency and Speed: A Practical Guide

Proxy latency decides how long your jobs run. Learn where the milliseconds go, how distance and handshakes add up, and how to measure and cut latency.

S SparkProxy 7 20 min read
Share
Proxy Latency and Speed: A Practical Guide

Proxy latency is the extra time your request spends because it travels through a middleman instead of going straight to the target. Most teams discover it the wrong way: a scraper that finished in 40 minutes on a direct connection takes three hours through a proxy pool, and nobody can say which part of the path is responsible. This guide breaks a proxied request into its timed phases, shows the physics floor set by geography, quantifies what TCP and TLS handshakes really cost, and gives you a measurement method that survives contact with production traffic.

Key takeaways

  • Latency is delay per request. Bandwidth is capacity per second. Adding bandwidth does nothing for a latency problem, and the two are measured with different tools.
  • Distance sets a hard floor. Light in fiber travels about 200,000 km/s, so roughly 1 ms of round-trip time per 100 km of path, before any equipment touches the packet.
  • A fresh HTTPS request through a proxy costs three round trips before the first request byte leaves. Connection reuse is usually the single largest speed win available to you.
  • Job duration is governed by latency divided by concurrency. A 30% latency cut and a 50% concurrency increase are not the same size of win, and the second one is often cheaper.
  • Report p50, p95, and p99. Average latency hides the tail that actually causes your timeouts.

Latency, Bandwidth, and Throughput Are Three Different Things

These get used interchangeably in provider marketing, and that's where most bad purchasing decisions start.

TermWhat it measuresUnitWhat improves it
LatencyDelay for one request to complete a round tripMillisecondsShorter path, fewer round trips, faster processing
BandwidthMaximum data volume the link can carry per secondMbps or GB/monthA bigger pipe, a less congested route
ThroughputData or requests you actually complete per secondreq/s or MbpsConcurrency, and only then latency

The distinction that matters: latency is a distance problem, bandwidth is a capacity problem. A proxy pool with 10 Gbps of egress can still feel slow if every exit IP sits 200 ms away from your target. A low-latency datacenter proxy on a saturated 100 Mbps port will crawl when you're pulling 5 MB HTML pages, even though its ping looks excellent.

Throughput sits on top of both. You can push high throughput over a high-latency link by running many requests in parallel, which is exactly what every serious scraper does. That's why the practical question is rarely "is this proxy fast" and usually "how many of these slow requests can I run at once." Provider concurrency ceilings are the constraint there, and they're covered in understanding concurrent connections in proxies.

One more term worth naming: jitter, the variance in latency between requests. A pool with a steady 180 ms is easier to work with than one that swings between 60 ms and 900 ms, because timeouts, retry budgets, and worker pool sizing all key off predictability rather than the mean.


Anatomy of a Proxied Request: Where the Milliseconds Go

A direct HTTPS request is client to target. A proxied HTTPS request is client to proxy to target, and every phase adds to the clock. Here's the full sequence for a typical HTTP proxy handling an HTTPS URL.

PhaseWhat happensTypical cost
DNS resolutionResolve the proxy hostname (the target is resolved by the proxy)0 ms cached, 20-80 ms cold
TCP handshake to proxySYN, SYN-ACK, ACK1 RTT to the proxy
Proxy authenticationCredentials validated, `CONNECT` tunnel opened1 RTT to the proxy
TLS handshake to targetClientHello through the tunnel to the origin1 RTT client-to-target (TLS 1.3), 2 RTT (TLS 1.2)
Request sent, target processingOrigin builds the response50-800 ms, entirely the target's doing
Time to first byteFirst response byte arrives back through the proxySum of everything above
Content transferRemaining bytes stream throughResponse size divided by throughput

Two things fall out of that table immediately.

First, the proxy adds round trips, not just distance. Even with a proxy sitting in the same city as you, the CONNECT step alone costs a round trip that a direct request never pays.

Second, target processing time is usually the biggest single number, and no proxy can fix it. If an origin takes 700 ms to render a product page, a proxy that adds 90 ms is responsible for 11% of your wait. Teams that switch providers chasing "faster proxies" without measuring the split frequently end up paying more for a 10% improvement in the wrong term.

The path also matters geometrically. Traffic goes client to proxy to target, so if your worker runs in Frankfurt, your exit IP is in Virginia, and the target's origin is in Frankfurt, you're crossing the Atlantic twice for a page that was next door. This triangle routing is the most common self-inflicted latency problem in geo-targeted scraping, and worth checking before you blame the provider. The reasoning behind picking an exit country is in what geo-targeting means in proxies.


Free trial

Scraping at scale? Skip the blocks.

Fast, unblockable datacentre proxies with unlimited bandwidth.

Geographic Distance and the Speed-of-Light Floor

There's a floor under every latency number, and no amount of provider engineering gets below it.

Light in a vacuum moves at about 299,792 km/s. Inside optical fiber it moves at roughly two thirds of that, near 200,000 km/s, because of the refractive index of glass. Round trip means the distance is covered twice. The useful shorthand:

Theoretical minimum RTT (ms) is approximately the path distance in km divided by 100.

Real paths aren't great circles. Fiber follows cable routes, coastlines, and peering agreements, and every router, amplifier, and switch adds queuing and serialization delay. Observed RTT typically lands 1.3x to 2x above the theoretical floor.

RouteGreat-circle distanceTheoretical RTT floorTypical observed RTT
Frankfurt to Amsterdam360 km3.6 ms8-12 ms
London to Frankfurt640 km6.4 ms14-20 ms
New York to Los Angeles3,940 km39 ms60-70 ms
New York to London5,570 km56 ms70-85 ms
London to Singapore10,850 km109 ms160-190 ms
New York to Sydney15,990 km160 ms200-240 ms
Sao Paulo to Frankfurt9,800 km98 ms180-210 ms

Read that table as a budget rather than trivia. If you're scraping a US-hosted target from a European worker through a US exit IP, you already owe roughly 75 ms per round trip on the transatlantic leg, and a fresh HTTPS connection spends three of them. That's 225 ms of pure geography before the origin server has done a thing.

The design lesson: put your worker close to your exit IP, and your exit IP close to the target's origin. When those three points form a line instead of a triangle, latency collapses without any change to your provider or plan.


Handshake Cost: TCP, CONNECT, and TLS

This is the part most latency guides skip, and it's the one you can actually control.

Opening a brand new HTTPS connection through a proxy costs three round trips before your request line is even transmitted:

  1. TCP handshake to the proxy. One RTT between your client and the proxy gateway.
  2. CONNECT tunnel setup. One more RTT to the proxy, including credential validation. A 407 Proxy Authentication Required challenge and retry adds another.
  3. TLS handshake to the target. With TLS 1.3 this is one RTT measured client-to-target through the tunnel, so it costs your client-to-proxy leg plus the proxy-to-target leg. TLS 1.2 needs two.

Put numbers on it. Say your client-to-proxy RTT is 30 ms and your proxy-to-target RTT is 50 ms, giving an end-to-end RTT of about 80 ms:

TCP to proxy         30 ms
CONNECT tunnel       30 ms
TLS 1.3 handshake    80 ms
--------------------------
Setup before request 140 ms

Now scale it. Ten thousand requests, each on a fresh connection, spend 1,400 seconds, about 23 minutes, doing nothing but handshakes. Reuse each connection for 50 requests and you open 200 connections instead of 10,000, dropping the same overhead to 28 seconds. Same proxy, same pool, same plan. The only change is a connection pool.

import requests

# Wrong: a fresh TCP + CONNECT + TLS handshake on every single call.
for url in urls:
    requests.get(url, proxies=PROXIES, timeout=30)

# Right: one Session reuses the tunnel across requests to the same host.
session = requests.Session()
session.proxies = PROXIES
adapter = requests.adapters.HTTPAdapter(
    pool_connections=20,   # distinct host pools kept alive
    pool_maxsize=50,       # sockets retained per pool
    max_retries=0,         # handle retries yourself, with backoff
)
session.mount("https://", adapter)

for url in urls:
    session.get(url, timeout=30)

There's a catch worth stating plainly, because it's the tradeoff nobody quantifies: per-request IP rotation and connection reuse are in direct conflict. If your pool assigns a new exit IP on every request, every request also pays a full handshake, since the old tunnel is gone. Sticky sessions keep the same exit IP and therefore the same warm tunnel for a window of time, which is why a sticky configuration often measures 100 to 200 ms faster per request than aggressive rotation on identical hardware. Choose rotation for block avoidance, choose stickiness for speed, and know which one you're buying. The mechanics of that window are in what a sticky session proxy is.

HTTP/2 changes the arithmetic in your favor when the target supports it, because many requests multiplex over one connection. SOCKS5 proxies skip the HTTP CONNECT exchange in favor of their own shorter negotiation, which saves a small amount of setup, though the dominant costs remain distance and TLS.


RTT, TTFB, and the Metrics Worth Tracking

Four numbers describe proxy speed. Confusing them is why benchmark arguments go nowhere.

  • RTT (round-trip time). How long a packet takes to reach a host and come back. This is what ping reports. It's a network-layer measure and it says nothing about whether the proxy can actually serve HTTP.
  • Connect time. How long to establish the TCP connection and, for HTTPS, complete TLS. Roughly two to three RTTs, and the number that connection reuse eliminates.
  • TTFB (time to first byte). From request sent to the first response byte received. This folds in the network path, the proxy's own processing, and the origin's think time. TTFB is the single most useful proxy speed metric because it captures everything that happens before data starts flowing.
  • Total response time. TTFB plus the time to transfer the full body. On large pages this is dominated by bandwidth, not latency, which is where bandwidth in proxy services becomes the relevant constraint instead.

Ping-based benchmarks are the classic mistake. Many proxy gateways deprioritize or drop ICMP entirely, so a 900 ms ping can sit in front of a 120 ms TTFB, or a beautiful 12 ms ping can front a gateway that takes 2 seconds to open a tunnel under load. Measure with real HTTP requests through the proxy, not with ping.

Then report percentiles, never the mean. A realistic distribution from a residential pool looks like this:

PercentileTTFBWhat it tells you
p50620 msThe typical experience
p901,450 msWhere retry logic starts to engage
p952,100 msThe right anchor for your timeout value
p998,400 msStragglers, dying IPs, and targets under load
Mean940 msMisleading, pulled up by the tail

Set your client timeout somewhere above p95 and below p99. Too tight and you kill requests that would have succeeded, burning credits and adding retry load. Too loose and a handful of dead connections hold worker slots hostage for 30 seconds each, which quietly destroys throughput. Anchoring on the mean gets you both problems at once.


Why Proxy Types Have Different Latency Profiles

Latency differences between proxy types aren't marketing. They come from where the IP physically lives and what it's connected to.

Proxy typeAdded latency vs directJitterWhy
Datacenter10-50 msLowServer-grade hardware in a data center on a backbone link
ISP (static residential)20-80 msLowResidential IP hosted on datacenter infrastructure
Rotating residential100-600 msHighTraffic exits through a real consumer device on a home connection
Mobile (4G/5G)150-900 msVery highCellular radio scheduling, carrier NAT, shared tower capacity

Datacenter proxies are quick because they never leave professional infrastructure. Residential proxies route through somebody's actual home connection, which adds the last-mile link, the consumer router, whatever else that household is doing, and the device's own scheduling. Mobile proxies add the radio access network on top, where scheduling intervals and signal conditions can single-handedly add hundreds of milliseconds.

That last-mile variability is why residential and mobile pools show high jitter rather than just a higher average. You're not measuring one network, you're sampling a different consumer device on every rotation. Two consecutive requests through the same pool can differ by an order of magnitude, and that's normal behavior rather than a fault. The full tradeoff picture across types is in the comparison of residential, datacenter, and mobile proxy types.

The engineering conclusion is uncomfortable but simple: the fastest proxy that gets blocked is slower than the slow one that succeeds. A datacenter IP returning a 403 in 40 ms has a real cost of 40 ms plus a full residential retry. Measure latency on successful, content-verified responses only, or you'll optimize toward the pool that fails quickest.


How to Measure Proxy Latency Properly

Start with curl, which exposes every phase boundary through its write-out variables. This one command tells you whether your problem is distance, handshakes, or the origin.

curl -o /dev/null -s \
  -x "http://USER:PASS@gateway.sparkproxy.io:11000" \
  -w "dns:        %{time_namelookup}s\ntcp_connect: %{time_connect}s\ntls_done:    %{time_appconnect}s\nttfb:        %{time_starttransfer}s\ntotal:       %{time_total}s\nsize:        %{size_download} bytes\n" \
  "https://example.com/"

The values are cumulative from the start of the request, so you subtract to get each phase:

  • time_connect minus time_namelookup is the TCP handshake to the proxy
  • time_appconnect minus time_connect is the CONNECT tunnel plus TLS to the target
  • time_starttransfer minus time_appconnect is target think time
  • time_total minus time_starttransfer is body transfer

If time_appconnect dominates, you have a handshake and distance problem, so reuse connections and move closer. If time_starttransfer dominates, the origin is slow and switching providers won't help. If time_total minus time_starttransfer dominates, you're bandwidth bound on large pages.

For a repeatable benchmark, sample properly and report percentiles:

import statistics
import time
import requests

PROXIES = {
    "http": "http://USER:PASS@gateway.sparkproxy.io:11000",
    "https": "http://USER:PASS@gateway.sparkproxy.io:11000",
}

def sample_ttfb(url, n=200, warmup=5):
    session = requests.Session()
    session.proxies = PROXIES
    samples = []
    for i in range(n + warmup):
        start = time.monotonic()
        try:
            r = session.get(url, stream=True, timeout=20)
            next(r.iter_content(1), None)       # block until the first byte lands
            ttfb = (time.monotonic() - start) * 1000
            r.close()
        except requests.RequestException:
            continue                            # excluded, count these separately
        if i >= warmup:                         # discard warm-up handshakes
            samples.append(ttfb)
    samples.sort()
    return {
        "n": len(samples),
        "p50": round(statistics.median(samples)),
        "p95": round(samples[int(len(samples) * 0.95) - 1]),
        "p99": round(samples[int(len(samples) * 0.99) - 1]),
    }

print(sample_ttfb("https://example.com/"))

Three rules keep this honest. Discard warm-up requests, since the first few carry handshake cost later ones won't. Sample at least 100 times, because residential jitter makes smaller samples meaningless. Benchmark from the machine that runs production, not your laptop.

If you're using the SparkProxy Scraping API, the server reports its own execution time and you don't have to infer it. Plain fetches return it as a response header, and headless jobs return it inside the JSON envelope.

import requests

r = requests.get(
    "https://scrape.sparkproxy.io/api/v1",
    headers={"X-API-Key": "sk-your-key"},
    params={"url": "https://example.com", "render_js": "false"},
    timeout=60,
)
# X-Duration-Ms is total server-side execution time for this job.
print(r.headers.get("X-Duration-Ms"), "ms server-side")
print(r.headers.get("X-Credits-Used"), "credits")

Subtracting the server-side duration from your own wall-clock measurement gives you the network time between your client and the API. That split tells you whether to move your worker or change your scraping parameters.


Cutting Latency Without Switching Providers

Ranked roughly by how much time they give back per hour of effort.

1. Reuse connections. Covered above, and typically worth 100 to 250 ms on every request after the first. Use a Session in Python, an http.Agent with keepAlive: true in Node, or a shared client in Go. Never construct a new HTTP client inside a loop.

2. Put the worker near the exit. If you're geo-targeting Germany, run the worker in Europe. Two Atlantic crossings per round trip is a self-inflicted 150 ms.

3. Skip the browser when you don't need it. Headless rendering is server-side execution time, not network latency, and it's usually the largest single component of a scraping API request. The SparkProxy API documents render_js=false as roughly 3x faster than a rendered fetch, at 1 credit instead of 5. Check whether the data you want is already in the raw HTML or in a JSON endpoint before you pay for Chromium.

4. Block what you don't parse. When rendering is genuinely required, stop loading assets you'll never read. Images, fonts, stylesheets, and ad scripts often account for most of a page's load time.

import requests

r = requests.get(
    "https://scrape.sparkproxy.io/api/v1",
    headers={"X-API-Key": "sk-your-key"},
    params={
        "url": "https://example.com/product/1234",
        "render_js": "true",
        "block_resources": "true",   # skip images, fonts, CSS, media
        "block_ads": "true",         # skip ad networks and trackers
        "wait_for": "#price",        # capture as soon as the data exists
        "json_response": "true",     # envelope carries duration_ms + status_code
    },
    timeout=90,
)
job = r.json()
print(job["status_code"], job["duration_ms"], "ms")

The wait_for selector matters more than it looks. A fixed wait of 3 seconds costs 3 seconds on every request, including the ones that were ready in 400 ms. Waiting on the selector that carries your data ends the job the moment the data exists.

5. Raise concurrency before chasing milliseconds. More on this below, and it's usually the cheapest lever available.

6. Prefer sticky sessions where the target allows it. One warm tunnel serving 50 requests beats 50 cold ones, as long as the target tolerates repeated requests from the same IP.

7. Match the proxy type to the requirement. Don't run residential proxies against a target that never blocked datacenter IPs. You're paying several hundred milliseconds per request for protection you don't need. A tiered approach, datacenter first with residential as fallback on block, gives most of the speed and most of the success rate.


The Latency Budget: When Speed Actually Decides Your Job

Here's the model that reframes the whole discussion. For a bulk job, wall-clock duration is approximately:

Total time = (number of requests x average per-request latency) / concurrency

Take a realistic shape of job: 250,000 product pages, 1.4 s average per request, 40 concurrent workers.

250,000 x 1.4 s / 40 = 8,750 s = about 2 hours 26 minutes

Now compare two optimizations. Cut per-request latency by 29%, from 1.4 s to 1.0 s, and you finish in 1 hour 44 minutes. Instead leave latency alone and raise concurrency by 50%, from 40 to 60, and you finish in 1 hour 37 minutes. The concurrency increase won, and it required no provider change, no code rewrite, and no move to faster infrastructure.

That's why latency obsession is often misplaced for batch work. Below a certain scale, concurrency is the dominant term, and the correct question is what's capping your parallelism: your plan's concurrent connection limit, your worker's file descriptors, the target's rate limiting, or your own thread pool. The failure modes of pushing past that ceiling show up in understanding proxy uptime and reliability, because a pool driven past its limit degrades before it fails outright.

Latency becomes the deciding factor in a specific set of cases:

  • Interactive and user-facing requests. A person is waiting. Anything above 1 s is felt, and above 3 s is abandonment territory.
  • Sequential dependencies. Log in, then navigate, then extract. Ten sequential steps at 800 ms is 8 seconds of unavoidable serial time, and concurrency can't compress it.
  • Time-boxed collection. Flight fares, betting odds, sneaker drops, ticket releases. A price you read 4 seconds late may not exist any more.
  • Deep pagination. Page N+1's URL comes from page N. The chain is serial by construction.
  • Concurrency you've already maxed out. Once you're at the ceiling of your plan or the target's tolerance, latency is the only remaining lever.

Work out which category you're in before you spend money on speed. For most bulk collection, buying more concurrent connections costs less than buying lower latency and delivers more. For a checkout monitor or a live odds feed, no amount of parallelism substitutes for a 90 ms round trip.


Frequently asked questions

FAQ

For datacenter proxies routed sensibly, 10 to 50 ms of added latency over a direct connection is normal, and TTFB under 300 ms against a fast target is healthy. Residential proxies typically add 100 to 600 ms because traffic passes through a real consumer connection, and mobile proxies can add more than a second. Judge proxy latency against the type you bought, not against a direct request.

Residential proxy traffic exits through an actual home internet connection, which adds the last-mile link, the household router, competing traffic on that connection, and the device's own scheduling. Datacenter proxies run on server hardware sitting directly on a backbone network. That structural difference produces both higher average latency and far higher jitter for residential pools.

It adds latency to every request and can cap throughput if the proxy's egress is congested, but a well-provisioned datacenter proxy on a nearby route costs only tens of milliseconds. The bigger slowdowns come from long geographic paths, repeated TCP and TLS handshakes on fresh connections, and rendering time on scraping APIs, not from the act of proxying itself.

Latency is the delay before data starts arriving, measured in milliseconds. Bandwidth is how much data the connection can move per second, measured in Mbps or as a monthly GB allowance. Latency governs how quickly a single request completes, and bandwidth governs how fast large responses transfer, so upgrading bandwidth won't fix a slow round trip.

Send real HTTP requests through the proxy rather than using ping, since many gateways deprioritize or drop ICMP. Use curl -w with time_connect, time_appconnect, and time_starttransfer to see each phase, sample at least 100 requests from the machine that runs production, discard warm-up requests, and report p50, p95, and p99 instead of the average.

Not always, because what matters is the total path from your worker to the exit IP to the target's origin. An exit IP near you but far from the target still crosses the long leg, and a geo-targeted exit can force two crossings if your worker sits on the wrong continent. Align worker, exit, and origin along one geography before optimizing anything else.


Special Discount ยท 20% off

Get 20% off your first month

Premium datacentre proxies with unlimited bandwidth. Use the code at checkout.

Save up to 15% more on quarterly, half-yearly and yearly plans

Claim Discount

About the Author

This guide was written by the SparkProxy Technical Team. SparkProxy operates datacenter proxies, residential proxies, and a managed Scraping API, and the team spends its days on the routing, connection pooling, and benchmarking work that keeps large-scale collection jobs finishing on time. We publish engineering-first explainers based on what we measure in production rather than on marketing numbers. Learn more at sparkproxy.io.

Keep reading

Related articles