How to Rotate Proxies in Python (2026 Guide)

By Marcus Reiner · 2026-05-11 · 14 min read · Engineering

#python#rotating#code

Rotating proxies in Python isn't hard — once you know the patterns. Here are the working code recipes for 2026.

EDITOR'S TOP PICK
Decodo
Smartproxy reborn — affordable premium proxies
From $2/GB · 4.7/5 stars · Trust Score 94/100
Visit Decodo → Read full review

How to rotate proxies in Python: the short answer

The most reliable way to rotate proxies in Python in 2026 is through a provider's backconnect gateway - a single hostname and port that automatically assigns a new IP per request or per session, so your code never manages an IP list directly. This works identically whether you use requests, httpx or aiohttp, since you simply point your proxy configuration at the gateway credentials rather than a list of individual IPs.

Client-side rotation through a manually maintained IP list is the legacy approach and is only worth using if you are self-hosting your own proxy pool or your provider does not offer a gateway; for anyone using a commercial provider like Decodo, the gateway method is simpler, more reliable and requires far less code.

Option 1: Backconnect gateway (recommended)

A backconnect gateway is a proxy endpoint - for example Decodo's gateway at gate.decodo.com on a fixed port - that sits in front of the provider's entire IP pool and rotates the exit IP automatically according to your account's rotation settings, without any code-side logic required.

Setting this up in Python with the requests library requires nothing more than passing the gateway URL with embedded credentials as your proxy dictionary; every request through that session can land on a different IP with zero additional code.

Option 2: Client-side IP list rotation

If you are managing your own list of proxy IPs rather than using a gateway, rotation means picking a different entry from that list on each request, typically using Python's random.choice or a round-robin index, and updating the requests proxies dictionary before each call.

This approach requires you to handle dead IP detection yourself - removing IPs that return connection errors or timeouts from the active pool - and to periodically refresh the list if your provider issues new IPs, adding meaningful maintenance overhead compared to a managed gateway.

Sticky sessions in Python

Sticky sessions hold the same exit IP for a configured duration, useful for multi-page scrapes or login flows that need consistency across several requests. With a gateway-based provider like Decodo, this is done by embedding a session identifier in the proxy username so the gateway maps that identifier to a fixed backend IP for the session's lifetime, typically up to 30 minutes.

In practice you generate a random session ID once per logical task, reuse the same requests.Session object with that session ID baked into the proxy credentials for every request in that task, then generate a fresh session ID for the next unrelated task to force a new IP.

Async rotation with aiohttp

For high-throughput scraping, asynchronous requests via aiohttp let you fire many concurrent requests through the rotating gateway, with each concurrent request naturally landing on a different IP since the gateway rotates per-connection by default.

The pattern is the same as with requests - pass the gateway URL as the proxy parameter on each request call - but wrapped in an asyncio.gather to run many requests concurrently, dramatically increasing throughput for large scraping jobs.

Rotation with httpx

httpx supports both sync and async clients with the same proxy configuration pattern as requests and aiohttp, and is a reasonable modern alternative for teams wanting HTTP/2 support alongside proxy rotation.

The proxy is configured once on the client instantiation rather than per-request, and because a single httpx.AsyncClient can be reused across many concurrent requests, it is a common choice for large async scraping pipelines built after 2023.

Retry logic and error handling

Proxy rotation is not a substitute for retry logic - even a high-quality provider will occasionally return connection errors, timeouts or non-200 status codes from a specific exit IP, and your scraper needs to handle these gracefully rather than treating them as fatal errors.

A standard pattern is to wrap each request in a retry loop with exponential backoff, generating a new session ID (forcing a new exit IP) on each retry, and giving up after a configured maximum attempt count while logging the failure for later analysis.

Common HTTP status codes and what they mean

429 (Too Many Requests) usually means your current IP has hit a rate limit on the target - rotate to a new IP and slow your request rate. 403 (Forbidden) often means the target's anti-bot system flagged the request outright, which may require a residential proxy upgrade or additional stealth measures rather than just a new IP.

407 (Proxy Authentication Required) means your proxy credentials are wrong or your IP is not whitelisted if the provider uses IP whitelisting instead of user/pass auth. Connection timeouts frequently indicate a dead or overloaded exit IP, which a gateway-based provider should route around automatically on the next request.

Common mistakes

The most common mistake is reusing the same requests.Session object across unrelated tasks without changing the session ID, which unintentionally keeps the same exit IP far longer than intended and defeats the purpose of rotation.

Another mistake is setting retry loops without any delay or backoff, hammering the target and the proxy gateway simultaneously and making rate-limiting worse rather than better.

Teams also frequently hardcode a single proxy configuration across an entire codebase rather than centralizing it in one config function, making it painful to switch providers or adjust rotation behavior later.

Verdict

For nearly all Python scraping workloads in 2026, use a provider's backconnect gateway rather than managing your own IP list - Decodo's gateway setup takes under five minutes and handles rotation, sticky sessions and dead-IP avoidance automatically. Pair it with proper retry logic and status-code-aware error handling, and consider Bright Data or Oxylabs if you need a managed unblocker layered on top for harder anti-bot targets.

Quick Comparison Top Providers
1
Bright Data
From $8/GB · 4.9/5
2
Oxylabs
From $8/GB · 4.8/5
3
Decodo
From $2/GB · 4.7/5
Compare all providers side by side →
EDITOR'S TOP PICK
Decodo
Smartproxy reborn — affordable premium proxies
From $2/GB · 4.7/5 stars · Trust Score 94/100
Visit Decodo → Read full review

Frequently Asked Questions

What is the easiest way to rotate proxies in Python?

Use a provider's backconnect gateway, such as Decodo's gate.decodo.com endpoint, which automatically rotates the exit IP per request or session without requiring you to manage an IP list in code.

How do I create sticky sessions in Python with rotating proxies?

Embed a session identifier in the proxy username, for example user-session-abc123, so the gateway maps that identifier to a fixed exit IP for a set duration, typically up to 30 minutes.

Can I rotate proxies with aiohttp for async scraping?

Yes, pass the gateway proxy URL to each request call within aiohttp, and concurrent requests will naturally use different IPs since gateway rotation happens per connection.

What should I do when I get a 429 status code?

Rotate to a new IP by generating a new session identifier, and add a delay between requests to the same target to avoid repeatedly triggering the rate limit.

Is client-side IP list rotation still worth using in 2026?

Only if you are self-hosting proxies or your provider lacks a gateway. For commercial providers like Decodo, gateway-based rotation is simpler and more reliable.

Related Resources on ToptierProxy