Modern anti-bot stacks are stateful. They correlate IP, TLS fingerprint, timing, and behavior. Beating them at scale is not about buying more proxies — it is about scheduling them coherently.
The threat model
- IP reputation scoring (residential > mobile > datacenter).
- TLS + HTTP/2 fingerprint clustering (JA3, akamai_fp).
- Behavioral timing signatures — humans are not Poisson.
- Session cookies bound to first-seen IP class.
Pool topology
Split proxies into pools by class. Never mix a residential and a datacenter IP inside the same session — that mismatch alone is a fingerprint. Each pool exposes the same interface: acquire(), release(ok=True|False).
The scheduler
Weighted round-robin with health scoring. Every proxy carries an EWMA of success rate over the last N requests; the scheduler biases toward the top quartile and quarantines anything under 60%.
def pick(pool):
healthy = [p for p in pool if p.ewma > 0.6]
weights = [p.ewma ** 2 for p in healthy]
return random.choices(healthy, weights=weights, k=1)[0]Fingerprints
Pair every proxy with a stable fingerprint bundle: user-agent, TLS profile (via curl_cffi), viewport, timezone. Rotate the bundle only when you rotate the IP class — never mid-session.
Adaptive backoff
On 429 or 403, quarantine the proxy for exponential time and inject jitter into the global request cadence. Do not retry immediately with a different proxy — that pattern itself is detectable.