The point that a proxy only changes IP reputation and nothing else is worth stressing. Some additions from running scrapers in production:
TLS fingerprinting is often the real blocker. With a clean residential IP, requests still gets flagged because its JA3/JA4 hash and HTTP/2 settings don’t match a browser. curl_cffi fixes this without a full headless browser:
Use socks5h://, not socks5://. The h makes DNS resolve on the proxy side. Otherwise your local resolver leaks and can reveal your real location.
Per-proxy cooldown beats a plain itertools.cycle. Track failures per proxy and bench an IP for a few minutes after repeated 403/429s, instead of rotating blindly into the same bad subnet.
Sticky sessions must match your cookie jar. If the exit IP changes while the session cookie stays the same, many sites invalidate the session. Tie one proxy to one Session object.
The cost-per-successful-request formula is the most practical part of the article. I’d also log p95 latency per target domain, since averages hide a lot.
TLS fingerprinting: Agreed, and it’s the thing I wish I’d stressed more. A clean residential IP doesn’t help if your JA3/JA4 hash and HTTP/2 settings scream “python-requests.” The curl_cffi snippet is a great addition because it avoids the overhead of a full headless browser for sites that only check the handshake.
socks5h vs socks5: Good catch. The DNS leak is easy to miss, and it quietly defeats the point of paying for geo-targeted IPs.
Per-proxy cooldown: Yes, plain itertools.cycle is fine for a demo but falls apart in production. Benching an IP after repeated 403/429s keeps you from hammering the same bad subnet.
Sticky sessions + cookie jar: This one bites people constantly. Pairing one proxy with one Session object is a simple rule that prevents a lot of mystery logouts.
p95 latency per domain: Adding this to my cost-per-successful-request tracking. Averages hide the slow tail, and that tail is usually where the real cost sits.
Really appreciate you sharing what’s worked in production. Comments like this are the reason I write these posts. 🙌
Thanks for the thoughtful reply! One more thing that ties into your cost-per-successful-request metric: count soft blocks as failures. A lot of sites return a 200 with a CAPTCHA or challenge page instead of a 403, so if you only count status codes, your success rate looks better than it really is. A quick check for known challenge markers in the body (or an unexpectedly small response size) fixes that.
Also, with curl_cffi, pin a specific profile like chrome120 instead of the chrome alias if you need reproducible runs. The alias moves when the library updates, and a silent fingerprint change can look like a sudden spike in blocks. Curious to see how the p95 numbers look once you start tracking them per domain.
Soft blocks: Great point, and it’s the kind of thing that quietly wrecks a dashboard. A 200 with a CAPTCHA page counts as a success if you only look at status codes, so the cost-per-successful-request number ends up flattering. I’ll add a body check for known challenge markers (and a minimum response size sanity check) and count those as failures. It also means the per-domain success rate will finally reflect what I actually got back, not just what the server said.
Pinning the curl_cffi profile: Good call. An alias that silently shifts with a library update is a nasty way to introduce a fingerprint change, and it would look exactly like a sudden block spike. Pinning something like chrome120 makes runs reproducible, and I can bump the version deliberately and compare block rates before and after.
I’ll share the p95-per-domain numbers once I have a decent sample. My guess is a couple of domains will look very different from what the averages suggest. Thanks again for the follow-up, this thread has turned into a better checklist than the original post. 🙌
One thing that helps when comparing providers is to measure them yourself instead of trusting marketing numbers. Run the same 200 requests through each provider against your actual target and record three things: success rate, p95 latency, and bytes per request.
Then plug the numbers into cost per success: (price_per_GB × GB_per_request) / success_rate. A cheaper per-GB provider with a lower success rate often ends up more expensive once retries are counted.
Two things to watch while benchmarking:
Time of day matters. Residential pools are peer devices, so latency and availability shift between peak and off-peak hours. Run the test at different times.
Block images, fonts and media in headless runs (Playwright’s page.route). On per-GB billing this can cut bandwidth by 60-80% on heavy pages.
Curious whether anyone has seen a big gap between datacenter and ISP proxies on the same target once TLS impersonation is in place.
Great suggestion, thanks for adding this. Measuring against your own target beats trusting marketing numbers, and cost per success is the metric that makes the comparison fair. I’d add one tweak to your script: log the failure types (403, 429, timeout, captcha page) alongside the success rate. Two providers with the same 80% can fail in very different ways, and that changes how you handle retries.
On your question about datacenter vs ISP proxies with TLS impersonation: in my experience the gap narrows a lot, but it doesn’t disappear. Impersonation fixes the fingerprint side (JA3/JA4, HTTP/2 settings), so targets that mainly check the client’s TLS signature stop flagging datacenter traffic as quickly. Targets that score IP reputation or ASN still tend to treat datacenter ranges as higher risk, and that’s where ISP proxies earn their price. So the answer depends on which of the two signals your target weighs more heavily.
Your benchmark is a good way to find out. Run the same 200 requests through a datacenter pool and an ISP pool with impersonation on, then compare cost per success rather than raw success rate. On lightly protected targets, datacenter often wins on cost. On heavily protected ones, ISP usually wins once retries are counted.
Good call on logging failure types. Here’s the tweak, with failures bucketed instead of swallowed:
fromcollectionsimportCounterdefclassify(r):ifr.status_code==200:body=r.text[:2000].lower()if"captcha"inbodyor"verify you are human"inbody:return"captcha_200"# soft block, still a 200
return"ok"returnstr(r.status_code)# 403, 429, 503...
# inside the loop:
# outcome = classify(r) -> Counter()[outcome] += 1
# except Exception -> Counter()["timeout"] += 1
The soft-block bucket matters most. Many targets return a 200 with a challenge page, so a plain status check overstates success rate. A pool that fails mostly on 429s needs slower rotation and backoff, while one that fails on 403s or captcha pages needs a different IP type.
On datacenter vs ISP: that split matches what I’d expect, and it’s why I’d run the benchmark per target rather than trust a general rule. [Add your own result here, e.g. “On X, datacenter with impersonation landed at around _% success vs _% for ISP, but ISP won on cost per success once retries were counted.” If you haven’t tested it yet, say so: “I haven’t run this head to head yet, so I’ll post numbers when I do.”]
One thing I’d add to the comparison: check whether the failures cluster by ASN or subnet. If one datacenter range gets burned, the whole pool degrades together, which a single success-rate number won’t show.
Thanks for the classifier, the captcha_200 bucket is the part I’d keep. One addition: keyword matching on the body will miss challenge pages that don’t use those words (JS challenges, “checking your browser” interstitials). Checking for a known marker on your target’s real pages, like a specific element or a minimum content length, is often more reliable than looking for block phrases.
The ASN/subnet clustering point is a good one. It’s easy to measure too. Log the exit IP per request (an IP echo endpoint, or the provider’s response headers if they expose it), then group outcomes by ASN or /24. If failures concentrate in a few ranges, you’re looking at a burned subnet, not a bad provider. It also tells you whether a provider’s pool is diverse enough to be worth the price.
I haven’t run the datacenter vs ISP comparison head to head on a shared target with impersonation on, so I’d rather not quote numbers from memory. When I do, I’ll post the success rate, failure breakdown and cost per success for both pools. If you’ve run it on any target, I’d like to see how your split looked.
The part on session control stood out to me. Many comparison posts skip over sticky versus rotating, but it decides whether a login flow works or gets challenged mid-session. The requests.Session example with one sticky IP and shared cookies shows that clearly.
I’d also add one point for anyone reading: when you rotate across a static IP list, put a cooldown on any proxy that returns repeated 403s or 429s. Otherwise one burned IP keeps getting picked and drags your success rate down.
Thanks for the legal note at the end as well. Checking ToS, robots.txt and GDPR/CCPA before scaling up is easy to forget.
Thanks, glad the sticky vs. rotating section was useful. Login flows are where a mid-session IP change bites hardest, so I wanted the requests.Session example to show the cookies and the IP staying together.
You’re right about cooldowns. The FAQ mentions dropping or cooling down a proxy after repeated 403/429s, but the rotation example doesn’t do it. It just does continue on a block, so with itertools.cycle a burned IP keeps coming back around. Here’s a fuller version:
Resetting strikes on success means one blip doesn’t bench a good IP. Honoring Retry-After when it’s present is better than a fixed cooldown.
Thanks for noting the legal section too. It’s easy to skip, and proxies don’t change what you’re allowed to collect. I’ll update the article to include the cooldown logic in the main example.
For proxy comparisons, the exit path deserves equal weight with the headline speed numbers. I’d include geography-specific p95 latency, failure classification, IP reputation recovery, and how quickly a customer can export routing rules or change providers. Those are the dimensions that show up during an incident, not just in a benchmark.
Great point, and I agree: speed benchmarks only tell you how a provider behaves when everything is healthy. The criteria you listed are what decide how bad an incident gets.
I leaned on headline speed and success-rate numbers because they’re easy to reproduce and compare across providers. That also means the article undersells the things that matter at 2 a.m. when a pool degrades:
Geography-specific p95 latency: a good global average can hide a slow tail in the one region your traffic depends on.
Failure classification: knowing whether a failure is a block, a timeout, a bad exit node, or an upstream error decides whether you retry, rotate, or fail over.
IP reputation recovery: how fast a flagged pool recovers matters more than how clean it looks on day one.
Exit path: being able to export routing rules and switch providers quickly is the best protection against lock-in, and few comparisons score it.
I’m going to add these as a separate “operational resilience” section to the comparison, so the ranking reflects incident behavior and not just benchmark speed. If you’ve seen specific providers handle failure classification or rule export well (or badly), I’d like to hear it. Thanks for the thoughtful addition.
One thing I left out of the article that causes a lot of confusion: a proxy only changes your IP reputation, not your fingerprint.
A clean residential IP still gets a 403 if your client sends a python-requests TLS fingerprint (JA3/JA4) with headers in the wrong order. A quick way to check whether the IP or the client is the problem is to run the same request three ways:
# 1) plain requests through the proxy
requests.get(url,proxies=p)# 2) TLS-impersonating client through the same proxy
fromcurl_cffiimportrequestsascrcr.get(url,proxies=p,impersonate="chrome")# 3) real browser through the same proxy (Playwright)
If #1 fails but #2 or #3 passes, the proxy is fine and you need to fix the client, not buy a more expensive plan.
Two other things I’d add:
Track cost per successful request, not price per GB. (price_per_GB × GB_per_request) / success_rate can flip the ranking. A cheaper pool with a lower success rate often costs more once you count retries.
Backoff matters more with rotation. If you rotate IPs but ignore Retry-After, you can get whole subnets flagged. Use exponential backoff with jitter, and cool down a proxy after repeated 403/429s instead of cycling straight back to it.
Curious what others are seeing: for sticky sessions on login flows, how long do your sessions actually hold before the target invalidates them? And are you routing by target (datacenter for easy sites, residential only for protected ones) or using one provider for everything?
The IP vs. fingerprint distinction is the one that trips people up most, and the three-way test is a clean way to isolate it. I’ll add a note to the article pointing to this comment.
On cost per successful request, I agree. Price per GB is misleading once you factor in retries and failed responses that still burn bandwidth. A pool at $8/GB with a 95% success rate can easily beat a $5/GB pool at 60%, especially on heavy pages.
The backoff point is underrated too. Rotating while ignoring Retry-After just spreads the damage across more IPs, and subnet-level flagging is hard to recover from. Cooling down a proxy after repeated 403/429s is much better than cycling back to it.
To your questions:
Sticky sessions: In my experience it varies a lot by target. Many login flows hold for roughly 10 to 30 minutes before something invalidates them, usually idle timeouts or a fingerprint/IP mismatch rather than a hard session cap. [Add your own numbers here if you have them.]
Routing: I route by target. Datacenter for easy or public endpoints, residential only for protected sites. Using residential for everything is the fastest way to overpay.
Curious what others are seeing too, especially anyone running long-lived sessions on login-heavy sites.
If most of your failures are soft_block on a clean residential IP, switching providers won’t help. The problem is your TLS/JA3 fingerprint or your header order. Try curl_cffi with impersonate="chrome" or a real Playwright session before paying for a more expensive pool.
Also, cooling down a proxy after 2-3 consecutive blocks, rather than just rotating, cut my retry cost noticeably on per-GB plans.
What are you all using to detect soft blocks: body-length heuristics, DOM selectors, or something else?
This is a great addition, thanks for sharing it. The benchmark in the NetNut section only counts status_code == 200 as a success, so a soft block gets scored as a win and a provider can look better than it is. Splitting failures by type is the right fix, and your point about soft blocks on a clean residential IP is the one I’d most like readers to take away. If the IP is fine and you still get captchas or stub pages, paying for a bigger pool won’t help. It’s the TLS/JA3 fingerprint or the header order, and curl_cffi with impersonate or a real Playwright session should come before any upgrade.
To answer your question, I’d layer the detection:
Per-target marker check. This is the most reliable one. Pick a string or selector that only appears on a real page (a product title, a price node, a JSON key) and treat its absence as a soft block.
Known challenge signatures. Look for strings like cf-chl, “Just a moment”, or the captcha provider’s script URLs in the body. It’s cheap and catches most of the obvious cases.
Body length against a per-target baseline. I’d use this last. A fixed 2000-byte cutoff will misfire on small JSON APIs and legitimate short pages, so compare against the typical size for that specific endpoint instead.
A small extension of your classifier along those lines:
defclassify(r,marker=None):ifr.status_codein(403,429):return"hard_block"ifr.status_code==200:body=r.text.lower()if"captcha"inbodyor"just a moment"inbody:return"soft_block"ifmarkerandmarkernotinr.text:return"soft_block"return"ok"returnf"http_{r.status_code}"
Your cooldown point is a good one too, since rotating straight away just spreads the damage across more IPs. What threshold and cooldown window do you use before bringing a proxy back? I’d like to compare numbers, because I’ve seen setups that never reintroduce a cooled-down IP and slowly shrink their own pool.
We're a place where coders share, stay up-to-date and grow their careers.
The point that a proxy only changes IP reputation and nothing else is worth stressing. Some additions from running scrapers in production:
requestsstill gets flagged because its JA3/JA4 hash and HTTP/2 settings don’t match a browser.curl_cffifixes this without a full headless browser:Use
socks5h://, notsocks5://. Thehmakes DNS resolve on the proxy side. Otherwise your local resolver leaks and can reveal your real location.Per-proxy cooldown beats a plain
itertools.cycle. Track failures per proxy and bench an IP for a few minutes after repeated 403/429s, instead of rotating blindly into the same bad subnet.Sticky sessions must match your cookie jar. If the exit IP changes while the session cookie stays the same, many sites invalidate the session. Tie one proxy to one Session object.
The cost-per-successful-request formula is the most practical part of the article. I’d also log p95 latency per target domain, since averages hide a lot.
TLS fingerprinting: Agreed, and it’s the thing I wish I’d stressed more. A clean residential IP doesn’t help if your JA3/JA4 hash and HTTP/2 settings scream “python-requests.” The
curl_cffisnippet is a great addition because it avoids the overhead of a full headless browser for sites that only check the handshake.itertools.cycleis fine for a demo but falls apart in production. Benching an IP after repeated 403/429s keeps you from hammering the same bad subnet.Sessionobject is a simple rule that prevents a lot of mystery logouts.Really appreciate you sharing what’s worked in production. Comments like this are the reason I write these posts. 🙌
Thanks for the thoughtful reply! One more thing that ties into your cost-per-successful-request metric: count soft blocks as failures. A lot of sites return a 200 with a CAPTCHA or challenge page instead of a 403, so if you only count status codes, your success rate looks better than it really is. A quick check for known challenge markers in the body (or an unexpectedly small response size) fixes that.
Also, with curl_cffi, pin a specific profile like
chrome120instead of thechromealias if you need reproducible runs. The alias moves when the library updates, and a silent fingerprint change can look like a sudden spike in blocks. Curious to see how the p95 numbers look once you start tracking them per domain.Soft blocks: Great point, and it’s the kind of thing that quietly wrecks a dashboard. A 200 with a CAPTCHA page counts as a success if you only look at status codes, so the cost-per-successful-request number ends up flattering. I’ll add a body check for known challenge markers (and a minimum response size sanity check) and count those as failures. It also means the per-domain success rate will finally reflect what I actually got back, not just what the server said.
Pinning the curl_cffi profile: Good call. An alias that silently shifts with a library update is a nasty way to introduce a fingerprint change, and it would look exactly like a sudden block spike. Pinning something like
chrome120makes runs reproducible, and I can bump the version deliberately and compare block rates before and after.I’ll share the p95-per-domain numbers once I have a decent sample. My guess is a couple of domains will look very different from what the averages suggest. Thanks again for the follow-up, this thread has turned into a better checklist than the original post. 🙌
One thing that helps when comparing providers is to measure them yourself instead of trusting marketing numbers. Run the same 200 requests through each provider against your actual target and record three things: success rate, p95 latency, and bytes per request.
Then plug the numbers into cost per success:
(price_per_GB × GB_per_request) / success_rate. A cheaper per-GB provider with a lower success rate often ends up more expensive once retries are counted.Two things to watch while benchmarking:
page.route). On per-GB billing this can cut bandwidth by 60-80% on heavy pages.Curious whether anyone has seen a big gap between datacenter and ISP proxies on the same target once TLS impersonation is in place.
Great suggestion, thanks for adding this. Measuring against your own target beats trusting marketing numbers, and cost per success is the metric that makes the comparison fair. I’d add one tweak to your script: log the failure types (403, 429, timeout, captcha page) alongside the success rate. Two providers with the same 80% can fail in very different ways, and that changes how you handle retries.
On your question about datacenter vs ISP proxies with TLS impersonation: in my experience the gap narrows a lot, but it doesn’t disappear. Impersonation fixes the fingerprint side (JA3/JA4, HTTP/2 settings), so targets that mainly check the client’s TLS signature stop flagging datacenter traffic as quickly. Targets that score IP reputation or ASN still tend to treat datacenter ranges as higher risk, and that’s where ISP proxies earn their price. So the answer depends on which of the two signals your target weighs more heavily.
Your benchmark is a good way to find out. Run the same 200 requests through a datacenter pool and an ISP pool with impersonation on, then compare cost per success rather than raw success rate. On lightly protected targets, datacenter often wins on cost. On heavily protected ones, ISP usually wins once retries are counted.
Have you seen a big gap on any of your targets?
Good call on logging failure types. Here’s the tweak, with failures bucketed instead of swallowed:
The soft-block bucket matters most. Many targets return a 200 with a challenge page, so a plain status check overstates success rate. A pool that fails mostly on 429s needs slower rotation and backoff, while one that fails on 403s or captcha pages needs a different IP type.
On datacenter vs ISP: that split matches what I’d expect, and it’s why I’d run the benchmark per target rather than trust a general rule. [Add your own result here, e.g. “On X, datacenter with impersonation landed at around _% success vs _% for ISP, but ISP won on cost per success once retries were counted.” If you haven’t tested it yet, say so: “I haven’t run this head to head yet, so I’ll post numbers when I do.”]
One thing I’d add to the comparison: check whether the failures cluster by ASN or subnet. If one datacenter range gets burned, the whole pool degrades together, which a single success-rate number won’t show.
Thanks for the classifier, the
captcha_200bucket is the part I’d keep. One addition: keyword matching on the body will miss challenge pages that don’t use those words (JS challenges, “checking your browser” interstitials). Checking for a known marker on your target’s real pages, like a specific element or a minimum content length, is often more reliable than looking for block phrases.The ASN/subnet clustering point is a good one. It’s easy to measure too. Log the exit IP per request (an IP echo endpoint, or the provider’s response headers if they expose it), then group outcomes by ASN or /24. If failures concentrate in a few ranges, you’re looking at a burned subnet, not a bad provider. It also tells you whether a provider’s pool is diverse enough to be worth the price.
I haven’t run the datacenter vs ISP comparison head to head on a shared target with impersonation on, so I’d rather not quote numbers from memory. When I do, I’ll post the success rate, failure breakdown and cost per success for both pools. If you’ve run it on any target, I’d like to see how your split looked.
The part on session control stood out to me. Many comparison posts skip over sticky versus rotating, but it decides whether a login flow works or gets challenged mid-session. The
requests.Sessionexample with one sticky IP and shared cookies shows that clearly.I’d also add one point for anyone reading: when you rotate across a static IP list, put a cooldown on any proxy that returns repeated 403s or 429s. Otherwise one burned IP keeps getting picked and drags your success rate down.
Thanks for the legal note at the end as well. Checking ToS,
robots.txtand GDPR/CCPA before scaling up is easy to forget.Thanks, glad the sticky vs. rotating section was useful. Login flows are where a mid-session IP change bites hardest, so I wanted the
requests.Sessionexample to show the cookies and the IP staying together.You’re right about cooldowns. The FAQ mentions dropping or cooling down a proxy after repeated 403/429s, but the rotation example doesn’t do it. It just does
continueon a block, so withitertools.cyclea burned IP keeps coming back around. Here’s a fuller version:Resetting strikes on success means one blip doesn’t bench a good IP. Honoring
Retry-Afterwhen it’s present is better than a fixed cooldown.Thanks for noting the legal section too. It’s easy to skip, and proxies don’t change what you’re allowed to collect. I’ll update the article to include the cooldown logic in the main example.
For proxy comparisons, the exit path deserves equal weight with the headline speed numbers. I’d include geography-specific p95 latency, failure classification, IP reputation recovery, and how quickly a customer can export routing rules or change providers. Those are the dimensions that show up during an incident, not just in a benchmark.
Great point, and I agree: speed benchmarks only tell you how a provider behaves when everything is healthy. The criteria you listed are what decide how bad an incident gets.
I leaned on headline speed and success-rate numbers because they’re easy to reproduce and compare across providers. That also means the article undersells the things that matter at 2 a.m. when a pool degrades:
I’m going to add these as a separate “operational resilience” section to the comparison, so the ranking reflects incident behavior and not just benchmark speed. If you’ve seen specific providers handle failure classification or rule export well (or badly), I’d like to hear it. Thanks for the thoughtful addition.
One thing I left out of the article that causes a lot of confusion: a proxy only changes your IP reputation, not your fingerprint.
A clean residential IP still gets a 403 if your client sends a python-requests TLS fingerprint (JA3/JA4) with headers in the wrong order. A quick way to check whether the IP or the client is the problem is to run the same request three ways:
If #1 fails but #2 or #3 passes, the proxy is fine and you need to fix the client, not buy a more expensive plan.
Two other things I’d add:
price_per_GB × GB_per_request) / success_ratecan flip the ranking. A cheaper pool with a lower success rate often costs more once you count retries.Retry-After, you can get whole subnets flagged. Use exponential backoff with jitter, and cool down a proxy after repeated 403/429s instead of cycling straight back to it.Curious what others are seeing: for sticky sessions on login flows, how long do your sessions actually hold before the target invalidates them? And are you routing by target (datacenter for easy sites, residential only for protected ones) or using one provider for everything?
The IP vs. fingerprint distinction is the one that trips people up most, and the three-way test is a clean way to isolate it. I’ll add a note to the article pointing to this comment.
On cost per successful request, I agree. Price per GB is misleading once you factor in retries and failed responses that still burn bandwidth. A pool at $8/GB with a 95% success rate can easily beat a $5/GB pool at 60%, especially on heavy pages.
The backoff point is underrated too. Rotating while ignoring
Retry-Afterjust spreads the damage across more IPs, and subnet-level flagging is hard to recover from. Cooling down a proxy after repeated 403/429s is much better than cycling back to it.To your questions:
Curious what others are seeing too, especially anyone running long-lived sessions on login-heavy sites.
One thing I couldn’t fit into the article: measure your block rate per failure type, not just overall success rate.
When you’re comparing providers, a flat “78% success” hides what’s actually failing. I log each response into one of three buckets:
Here’s a minimal classifier you can drop into the benchmark function from the NetNut section:
If most of your failures are
soft_blockon a clean residential IP, switching providers won’t help. The problem is your TLS/JA3 fingerprint or your header order. Trycurl_cffiwithimpersonate="chrome"or a real Playwright session before paying for a more expensive pool.Also, cooling down a proxy after 2-3 consecutive blocks, rather than just rotating, cut my retry cost noticeably on per-GB plans.
What are you all using to detect soft blocks: body-length heuristics, DOM selectors, or something else?
This is a great addition, thanks for sharing it. The benchmark in the NetNut section only counts
status_code == 200as a success, so a soft block gets scored as a win and a provider can look better than it is. Splitting failures by type is the right fix, and your point about soft blocks on a clean residential IP is the one I’d most like readers to take away. If the IP is fine and you still get captchas or stub pages, paying for a bigger pool won’t help. It’s the TLS/JA3 fingerprint or the header order, andcurl_cffiwith impersonate or a real Playwright session should come before any upgrade.To answer your question, I’d layer the detection:
cf-chl, “Just a moment”, or the captcha provider’s script URLs in the body. It’s cheap and catches most of the obvious cases.A small extension of your classifier along those lines:
Your cooldown point is a good one too, since rotating straight away just spreads the damage across more IPs. What threshold and cooldown window do you use before bringing a proxy back? I’d like to compare numbers, because I’ve seen setups that never reintroduce a cooled-down IP and slowly shrink their own pool.