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

What Proxy Success Rate Means and How to Measure It Yourself

Proxy success rate is measured at three different layers and vendors publish the flattering one. Here is what it hides and how to measure yours properly.

S SparkProxy 2 17 min read
Share
What Proxy Success Rate Means and How to Measure It Yourself

Proxy success rate is the least standardised number in proxy marketing. Two vendors can both print "99.9%" and mean different things, because one counts whether its gateway accepted your connection and the other counts whether a target returned any HTTP response at all. Neither counts the thing you pay for: whether the response contained the data you asked for. This post defines the three layers the number hides, shows why status codes overstate success, gives the sample size a trial needs before its result means anything, and ends on the only figure that belongs in a purchase decision, cost per successful record.

The short answer

Do not buy on a published success rate. It was measured on the vendor's infrastructure, against the vendor's choice of target, at whichever layer flatters them, and it is not a property you can purchase. Success rate belongs to a pair: this pool against that target, this week. Change either half and the number changes.

The number worth acting on is the one you measure, on your own URLs, with failures classified instead of counted. That fits in an afternoon of setup and 24 hours of running: freeze 500 to 2,000 real URLs per target class, run both candidate providers through the same code path, classify every outcome into a fixed taxonomy, then report two rates rather than one and convert both into dollars per thousand successful records. Everything below is that procedure, plus the traps that make most trials produce a figure nobody should trust.


Three layers hide behind one number

Success gets measured at three places in the request path, and they diverge badly.

LayerCounts as success whenWho reports itWhat it hides
1. GatewayThe proxy authenticated you and opened a tunnel to the target host and portVendor status pages, uptime figures, most published success ratesEverything the target did afterwards
2. TransportThe target returned an HTTP response, usually any 2xxYour scraper's logs, most off-the-shelf dashboardsBlocks that arrive with a 200 status
3. DataThe response parsed and contained the field you neededNobody, unless you build itNothing, this is the number that pays

Layer 1 sits close to 100% for any provider still in business, which is exactly why it is the layer that gets published. A gateway that accepts your credentials and returns 200 Connection Established has told you one thing: a TCP tunnel opened. It has not told you that TLS completed, that the origin answered, or that the answer was worth keeping. That figure is closer to availability than to success, and it deserves the name it gets in understanding proxy uptime and reliability.

Layer 2 is where most teams stop, because a status code is free to log, and it is where the measurement quietly breaks. Layer 3 is the only layer with a currency attached. A row you can insert into your database is worth something. A 200 response containing a challenge page is worth less than nothing, because you paid for the bytes and then paid an engineer to notice.


Free trial

Scraping at scale? Skip the blocks.

Fast, unblockable datacentre proxies with unlimited bandwidth.

The soft 200 problem

Modern anti-bot systems mostly stopped returning 403. An error status tells the scraper it was caught, so the defences that cost the most money now return HTTP 200 with a challenge page, an empty product shell, a stripped listing, or a geo-redirected page in the wrong currency. Every one of those is a success at layer 2 and a failure at layer 3.

The consequence: any success rate computed from status codes is an upper bound, never an estimate. If your dashboard says 97% and your pipeline is short on rows, the gap is soft blocks, not a mystery. The fix is a classifier that makes a positive assertion instead of checking for the absence of an error.

Observed outcomeTypical signalRetry on a new exit?Layer 3 success?
Connection refused or tunnel errorNo HTTP status at allYes, different exitNo
Read timeout past your ceilingNo response bytesYes, with backoffNo
407 Proxy Authentication RequiredCredentials or IP whitelist wrongNo, fix the config firstNo
403 or 429Explicit block or rate limitYes, slower and on a new IPNo
200 carrying challenge markupKnown challenge strings, body under a few KBYes, different exit classNo
200, correct layout, required field absentParser returns nothing for the selectorOnly once, then treat as genuineNo
200 with every required field presentParse succeedsNot applicableYes

The second-to-last row is the expensive one. A product that is genuinely out of stock and one hidden by a block look identical to a naive parser, so a blind retry policy burns budget rediscovering an absence. Cap retries on that class at one and log it separately. The difference between an explicit refusal and a silent one is worked through in how to detect when your scraper is blocked, and the codes themselves are catalogued in proxy error codes explained.

One rule carries most of the value here: define success as a field you found, never as an error you did not see.


Per attempt or per record

There are two success rates and they answer different questions. Reporting one collapses them and hides whichever is about to hurt you.

Per-attempt rate is successes divided by every request you sent, retries included. It drives cost, because your bill counts attempts.

Per-record rate is records obtained divided by records wanted. It drives coverage and schedule, because a missing row is missing no matter how many times you tried for it.

Retries convert one into the other. With a per-attempt rate of p and independent attempts, you need 1/p attempts per record on average, and the chance of landing a record within k tries is 1 - (1 - p)^k.

Per-attempt rateAttempts per recordRecord rate after 3 tries
95%1.0599.99%
80%1.2599.2%
60%1.6793.6%
40%2.5078.4%
20%5.0048.8%

Read that table with its assumption visible. Independence between attempts is optimistic. If the block is keyed to your TLS fingerprint, your header order, or the whole /24 your exits came from, retries correlate and the real record rate sits below the column above. That is a modelling limit, not a measurement, and it is why a retry policy has to change something between attempts rather than repeat the same request faster. Backoff shape and jitter are covered in retry and backoff strategies for web scraping, and the timeout that decides what counts as a failure at all is in proxy timeouts and retry logic.

A vendor quoting 99% at layer 1 while you observe 60% per attempt at layer 3 is not necessarily lying. They are answering a question you did not ask.


How big a test needs to be

A trial result is an estimate with error bars, and almost nobody prints the error bars. For a proportion, the 95% confidence interval is roughly 1.96 sqrt(p (1 - p) / n).

Requests in the testMargin at ~95% observedMargin at ~99% observed
100plus or minus 4.3 pointsplus or minus 2.0 points
500plus or minus 1.9 pointsplus or minus 0.9 points
2,000plus or minus 1.0 pointplus or minus 0.4 points
10,000plus or minus 0.4 pointsplus or minus 0.2 points

This is the arithmetic that quietly ruins free trials. A 100-request sample can prove a pool is broken, because a 40% result at that size is unambiguous. It cannot separate a 95% pool from a 99% pool, and that difference is a 4% swing in your cost per record for as long as you stay on the plan.

Two constraints the formula does not capture. Sample size is per target class, not in total, so 2,000 requests split across five sites is 400 each and back in the useless band. And it assumes independent draws, while scraping outcomes are correlated in time, since a target's defence posture shifts by hour of day and by deploy. Spread the test across at least 24 hours including the target's peak, otherwise the interval is narrower than the truth.


Measure it yourself

The harness is small. The classifier is the part worth arguing about.

CHALLENGE = ("captcha", "are you human", "cf-browser-verification",
             "px-captcha", "checking your browser")

def classify(status, body, required):
    """Return one outcome label per attempt. Never return a boolean."""
    if status is None:
        return "transport_error"
    if status == 407:
        return "auth_error"
    if status in (401, 403):
        return "blocked"
    if status == 429:
        return "rate_limited"
    if status >= 500:
        return "origin_error"
    if status != 200:
        return f"http_{status}"

    low = body.lower()
    if len(body) < 2000 or any(s in low for s in CHALLENGE):
        return "soft_block"
    if required not in body:
        return "missing_field"
    return "ok"

Point it at real production URLs, not a homepage. SparkProxy's Scraping API returns the fetched page body and puts the accounting on the response headers, which ties outcomes to spend:

import time
import requests
from collections import Counter

API = "https://scrape.sparkproxy.io/api/v1"
HEADERS = {"X-API-Key": "sk-YOUR_API_KEY"}

def probe(url, required, country="US"):
    try:
        r = requests.get(
            API,
            headers=HEADERS,
            params={
                "url": url,
                "render_js": "false",     # plain fetch, 1 credit
                "country_code": country,  # ISO 3166-1 alpha-2
            },
            timeout=60,
        )
    except requests.RequestException:
        return "transport_error", 0, 0

    credits = int(r.headers.get("X-Credits-Used") or 0)
    ms = int(r.headers.get("X-Duration-Ms") or 0)
    return classify(r.status_code, r.text, required), credits, ms

counts, spent = Counter(), 0
for url in URLS:                       # 2,000 real URLs, sampled like production
    outcome, credits, ms = probe(url, required='"price"')
    counts[outcome] += 1
    spent += credits
    time.sleep(0.2)

attempts = sum(counts.values())
print(dict(counts))
print("per-attempt success:", round(counts["ok"] / attempts, 4))
print("credits spent:", spent)

Add json_response=true if you would rather have a structured envelope than the raw page. That form returns job_id, status_code, duration_ms and credits_used as fields plus a meta object. Set premium_proxy=true to send the same probe through residential exits, and render_js=true when the field only exists after JavaScript runs, remembering that a rendered fetch costs 5 credits against 1 for a plain one.

Testing raw gateway access instead of the API is the same classifier with a different transport:

PROXY = "http://user-12345:s3cr3t@gateway.sparkproxy.io:11000"

r = requests.get(target, proxies={"http": PROXY, "https": PROXY}, timeout=15)

Port 11000 rotates per request, 11002 holds a sticky session, and 13000 is SOCKS5. Test on the port production will use, because rotation and stickiness produce genuinely different success rates against a target that tracks session consistency.

Log one row per attempt, not per record: timestamp, target class, country, outcome label, response bytes, duration in milliseconds, credits or bytes billed, and the attempt index. Without that index you can never separate the two denominators. Broader methodology sits in how to test proxies, with the faster smoke test in how to test if your proxy is working.


From success rate to cost per record

Success rate matters because it multiplies price. SparkProxy's Scraping API Growth tier is $99 for 1,000,000 credits, a plain fetch costs 1 credit and a JavaScript render costs 5, so a credit is $0.000099.

Per-attempt successAttempts per 1,000 recordsPlain fetch, per 1,000 recordsJS render, per 1,000 records
95%1,053$0.10$0.52
80%1,250$0.12$0.62
60%1,667$0.17$0.83
40%2,500$0.25$1.24

That model assumes every attempt bills, which is the conservative reading. It is arithmetic on published prices, not a measurement of anything, and failure billing is a question to put to any vendor in writing before you build your own version of the table.

Two things fall out of it. Plan sizing follows records divided by success rate, not record count: a 1,000,000 credit plan at 80% per-attempt success delivers 800,000 plain-fetch records, so the tier you need is set by a block rate you have not measured yet. And the render multiplier dominates everything else, since a rendered workload at 60% success burns 8.3 times the credits of a plain fetch at 100%. The highest-value optimisation is usually finding the JSON endpoint behind the page, not shopping for a better pool.

Thread-metered plans behave differently, and that is worth knowing before you pick a billing model. On a plan metering concurrent threads with unlimited bandwidth, a failed request costs a thread-second and no money: at 60% per-attempt success, 100 threads deliver the useful throughput of 60, so the block rate becomes a schedule problem instead of an invoice problem. On a per-gigabyte plan the same 40% failure rate is a direct 40% price increase, because block pages transfer bytes and bytes are the unit. Each model is laid out in understanding datacenter proxy pricing models.


Reading a vendor's proxy success rate claim

Vendor marketing pages, as a general pattern in September 2026, publish a single unqualified percentage with no layer, no target, no window and no sample size attached. Treat any such figure as unstated until the vendor states it, and check their current page yourself rather than trusting a number quoted in an article, this one included.

Ask the vendorWhy it decides the purchaseAnswer that should worry you
Which layer is that measured atLayer 1 is nearly free to achieve"Network success rate", undefined
Against which targetsA rate on a test endpoint transfers to nothing"Across our network"
Over what window and what sample sizeOne good hour proves nothingNo window offered
Are failed requests billedIt is a hidden multiplier on your real priceVague, or "it depends"
Is there a written replacement policy for dead IPsDecides who absorbs pool decayHandled case by case
Can I run 2,000 requests before paying, on which planTrial size decides whether you can measure anythingTrial capped far below that

The honest position: no provider can promise a success rate against a third-party site they do not control. What a provider can commit to is gateway availability, pool composition, geographic coverage, session behaviour and a replacement policy for bad addresses. Anyone promising a layer 3 number against a named retailer or search engine is either quietly measuring layer 1 or writing a claim they cannot enforce. A broader checklist is in what to evaluate when selecting a proxy service.


Running a fair trial across two providers

Most head-to-head trials measure the target rather than the providers. The fix is mechanical.

  1. Freeze the URL set first. 500 to 2,000 real production URLs per target class, sampled the way your pipeline samples.
  2. Change exactly one thing. Same parser, same headers, same concurrency, same timeout ceiling. Only the proxy configuration differs.
  3. Interleave the providers request by request. Running A on Monday and B on Wednesday compares two days, not two pools, and it is the most common way a trial produces a wrong answer.
  4. Run for at least 24 hours, with the window covering the target's peak.
  5. Classify with the same code for both. No manual triage, because that is where flattering bias enters.
  6. Report per-attempt and per-record separately, each with the confidence interval its sample size earns.
  7. Convert both into cost per 1,000 successful records using each vendor's actual billing unit. Threads, gigabytes and credits are not comparable until you do.
  8. Re-run before every renewal. Pools decay and targets update their defences, so last quarter's winner is not evidence about this quarter.

To rehearse the classifier before committing budget, SparkProxy's Scraping API includes 1,000 free credits with no card, which buys 1,000 plain fetches or 200 rendered pages. Be clear about what that covers: enough to validate your outcome labels and catch a pool that is outright broken, not enough for a one-point comparison between two decent providers.


Where SparkProxy fits, and where it does not

SparkProxy sells datacenter proxies from a pool of over 1,000,000 IPs across 80+ countries, including more than 50,000 US addresses, reached through gateway.sparkproxy.io on port 11000 for HTTP and HTTPS, 11002 for sticky sessions and 13000 for SOCKS5. Plans are metered by concurrent threads rather than traffic: Starter $75 for 100 threads and 5 whitelist slots, Core $140 for 250 threads and 10 slots, Boost $240 for 500 threads and 15 slots, Plus $440 for 1,000 threads and 25 slots, each with unlimited bandwidth over 30 days. The fair usage policy caps throughput per tier at 25, 50, 100 and 150 Mbps respectively, with Pro and Pro+ tiers at 200 and 250 Mbps and custom arrangements up to 1 Gbps. Those caps are ceilings, not guaranteed rates.

That shape matters here because with bandwidth unmetered, a bad success rate cannot inflate the invoice. It costs threads and wall-clock time instead, both recoverable by scheduling. If your block rate is unpredictable, that difference is often worth more than the headline price gap.

Where a datacenter pool is the wrong purchase: targets that score the exit ASN and refuse hosting ranges outright. On those, no amount of thread count fixes a layer 3 rate, and the answer is residential exits, which the Scraping API reaches with premium_proxy=true, or a different collection approach entirely. The trade-offs are set out in residential vs datacenter proxies, and the build-versus-buy question is covered in web scraping API vs self-managed proxies.

Measure both on your own URLs before paying the residential premium. That is this whole post applied to the decision it most often changes.


Frequently asked questions

FAQ

There is no universal figure, because the number only means something against a named target at a named layer. As a working frame, undefended and lightly defended targets should land in the high 90s at layer 3, and anything below roughly 90% there points at your configuration rather than the pool. On heavily defended commercial sites, a 50 to 80 percent per-attempt rate can still be economic if retries are cheap relative to the value of a record.

Almost always because you are measuring a different layer. Their figure typically counts gateway connections that succeeded, yours counts pages that parsed. Add a target the vendor never tested against, plus soft blocks that arrive with a 200 status, and a genuine 99.9% at layer 1 sits comfortably alongside 60% at layer 3.

It depends entirely on the billing unit. On a per-gigabyte plan you pay for the bytes of the block page, so the block rate is a straight price increase. On a thread-metered plan with unlimited bandwidth it costs capacity and time rather than money. On credit-metered APIs, ask the vendor in writing whether failures consume credits and never assume they are free.

Around 2,000 per target class gets you roughly one point of margin at a 95 percent observed rate. One hundred requests gives about four points, which cannot separate a 95 percent pool from a 99 percent one. Spread the sample across at least 24 hours so it covers the target's peak, and count 2,000 per site rather than 2,000 in total.

No. Uptime measures whether the provider's gateway was reachable and authenticating, which is layer 1 and nearly always high. Success rate as a buyer should define it measures whether requests came back with usable data, which depends on the target as much as the provider. A provider can hold 100 percent uptime through a week in which your success rate collapses.

No. On targets that do not score the exit ASN, datacenter proxies frequently match residential results at a fraction of the price and with much lower latency. Residential exits win specifically where hosting ranges are refused outright. The only way to know which case you are in is to run both through the same classifier on your own URLs.


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

The SparkProxy Technical Team builds and operates SparkProxy's datacenter proxy network, residential proxy pools and Scraping API for developers and data teams running collection at scale. We write about the measurement and cost mechanics behind proxy infrastructure because those decide whether a pipeline pays for itself. Full API parameters and current plan details are in the Scraping API documentation.

Keep reading

Related articles