Rotating proxies assign a new IP address on every request. Sticky proxies keep the same IP for a defined period (typically 1-30 minutes). Picking the wrong type doesn't just reduce efficiency — it can actively cause failures. A multi-step checkout flow with rotating IPs will break because the server sees different IPs mid-session. A bulk scraping job with sticky IPs will get flagged because 500 requests from one IP in 10 minutes is abnormal residential behavior.
Here's the decision framework based on real usage patterns.
Quick Decision Table
| Use case | Proxy type | Why |
|---|---|---|
| Scraping product pages (independent URLs) | Rotating | Each request is standalone, max IP diversity |
| Scraping search results (pagination) | Rotating | Pages are independent, no session state |
| Login → navigate → scrape | Sticky | Server tracks session by IP |
| Multi-step checkout flow | Sticky | IP change mid-checkout = instant flag |
| Account creation | Sticky | Registration flow spans multiple requests |
| Social media account management | Sticky | Platform ties session to IP |
| Price comparison across regions | Rotating + geo | Different IP per region, no session needed |
| SERP monitoring | Rotating + geo | Independent queries, max diversity |
| Ad verification | Rotating + geo | Need many IPs to see different ad variants |
| Sneaker/ticket purchasing | Sticky | Cart → checkout is stateful |
How Rotating Proxies Work
With a gateway proxy, rotation happens automatically. Each new TCP connection through the gateway gets assigned a different exit IP from the pool.
import requests
# Each request gets a new IP — no session ID in the username
proxy = {
'http': 'http://your-username:[email protected]:8080',
'https': 'http://your-username:[email protected]:8080',
}
for i in range(5):
r = requests.get('https://httpbin.org/ip', proxies=proxy)
print(f"Request {i+1}: {r.json()['origin']}")
# Output: 5 different IPs
When Rotating Proxies Excel
Bulk data collection: Scraping 10,000 product pages where each URL is an independent request. Every request goes through a different IP, so even if one IP gets flagged, it only affects that single request. Your overall success rate stays high.
Search engine scraping: Each search query is standalone. You want maximum IP diversity to avoid rate limits and get unbiased results. With 30M+ IPs in the ProxyLabs pool, you can run thousands of queries without repeating an IP.
Data verification: Checking prices, stock levels, or content from many different IPs to verify you're seeing the same data that real users see (some sites serve different content to repeated visitors).
Rotating Proxy Pitfalls
Session-dependent pages: If the site sets a cookie on request 1 and expects the same IP on request 2, rotation breaks the flow. This includes most login-protected content, shopping carts, and multi-page forms.
Rate-limited APIs: Some APIs rate-limit per IP per minute. With rotating IPs, you might hit the same exit IP twice by chance and trigger a limit. For APIs, sticky sessions with a dedicated IP per worker thread is more predictable.
How Sticky Proxies Work
Sticky sessions maintain the same exit IP for a time window. With ProxyLabs, you add a session ID to the username — all requests with that session ID route through the same IP for up to 30 minutes.
import requests
# Same session ID = same IP for 30 minutes
proxy = {
'http': 'http://your-username-session-abc123:[email protected]:8080',
'https': 'http://your-username-session-abc123:[email protected]:8080',
}
for i in range(5):
r = requests.get('https://httpbin.org/ip', proxies=proxy)
print(f"Request {i+1}: {r.json()['origin']}")
# Output: same IP all 5 times
When Sticky Proxies Excel
Login flows: The server ties your session cookie to your IP. If the IP changes between the login POST and the next authenticated request, the session is invalidated. Most sites with user accounts do this.
import requests
import uuid
session = requests.Session()
session_id = uuid.uuid4().hex[:12]
proxy = {
'http': f'http://your-username-session-{session_id}:[email protected]:8080',
'https': f'http://your-username-session-{session_id}:[email protected]:8080',
}
# Login
session.post('https://example.com/login',
data={'email': '[email protected]', 'password': 'pass'},
proxies=proxy
)
# Subsequent requests use the same IP — session cookie stays valid
dashboard = session.get('https://example.com/dashboard', proxies=proxy)
settings = session.get('https://example.com/settings', proxies=proxy)
Account management: Managing multiple social media accounts requires each account to have a consistent IP. If account A always connects from IP 1 and account B always connects from IP 2, they look like separate users. If both cycle through random IPs, the platform may link them.
E-commerce checkout: Cart → shipping → payment → confirmation is a multi-step flow where the server expects IP consistency. Mid-flow IP changes trigger fraud detection on most e-commerce platforms.
For a detailed guide on sticky session patterns, see our sticky sessions guide.
Sticky Proxy Pitfalls
Long scraping jobs: If you're scraping 1,000 pages with the same sticky IP, the target site sees 1,000 requests from one residential IP in 30 minutes — that's not normal residential behavior. You'll get rate-limited or blocked.
IP goes offline: Residential IPs come from real devices. If the device disconnects, your sticky session loses its IP. Good proxy providers handle this by auto-reassigning, but there may be a brief interruption. Build retry logic for this.
Hybrid Approach: Rotating + Sticky
Most real scraping jobs need both. The pattern: use rotating IPs for the bulk scraping work, switch to sticky for any stateful flows.
import requests
import uuid
PROXY_BASE_USER = 'your-username'
PROXY_PASS = 'your-password'
PROXY_HOST = 'gate.proxylabs.app:8080'
def rotating_proxy(country=None):
"""Get proxy config with a new IP per request."""
user = PROXY_BASE_USER
if country:
user += f'-country-{country}'
return {
'http': f'http://{user}:{PROXY_PASS}@{PROXY_HOST}',
'https': f'http://{user}:{PROXY_PASS}@{PROXY_HOST}',
}
def sticky_proxy(session_id=None, country=None):
"""Get proxy config with a persistent IP."""
user = PROXY_BASE_USER
if not session_id:
session_id = uuid.uuid4().hex[:12]
user += f'-session-{session_id}'
if country:
user += f'-country-{country}'
return {
'http': f'http://{user}:{PROXY_PASS}@{PROXY_HOST}',
'https': f'http://{user}:{PROXY_PASS}@{PROXY_HOST}',
}
# Phase 1: Rotating IPs to collect product URLs
product_urls = []
for page in range(1, 20):
r = requests.get(
f'https://example.com/products?page={page}',
proxies=rotating_proxy('US'),
timeout=15,
)
# Parse product URLs from response...
product_urls.extend(parse_urls(r.text))
# Phase 2: Sticky IP per product for detail + price + reviews
for url in product_urls:
sid = uuid.uuid4().hex[:8]
proxy = sticky_proxy(session_id=sid, country='US')
session = requests.Session()
detail = session.get(url, proxies=proxy, timeout=15)
reviews = session.get(url + '/reviews', proxies=proxy, timeout=15)
# Same IP for both requests — looks like a real user browsing
Bandwidth Considerations
Sticky and rotating sessions use the same bandwidth. The cost difference comes from efficiency:
| Scenario | Rotating | Sticky | Why |
|---|---|---|---|
| 1,000 independent pages | 1× bandwidth | 1× bandwidth | Same data either way |
| Login + 50 pages (session needed) | 2-3× bandwidth (retries from failed auth) | 1× bandwidth | Rotating breaks sessions, causes retries |
| 100 URLs, strict rate limit (5/min/IP) | 1× bandwidth | 1× bandwidth | But sticky requires 20 IPs at 5 req each |
With ProxyLabs, bandwidth is priced the same regardless of session type — starting at £2.50/GB on the 100GB tier. The economic decision is about minimizing wasted bandwidth from failed requests, not about session pricing.
How to Set Sessions in Different Tools
| Tool | Rotating | Sticky |
|---|---|---|
| requests (Python) | No session modifier | -session-{id} in username |
| Scrapy | Default behavior | request.meta['proxy_session'] |
| Playwright | Default behavior | Add -session-{id} to username |
| Puppeteer | New page.authenticate() per page | Same page.authenticate() with fixed session |
| cURL | Default behavior | -session-{id} in username |
For tool-specific setup, see our integration guides: Playwright, Selenium, Puppeteer, Scrapy, or cURL.
Ready to try the fastest residential proxies?
Join developers and businesses who trust ProxyLabs for mission-critical proxy infrastructure.
Building proxy infrastructure since 2019. Previously failed at many things, now failing slightly less.
Related Articles
Scrapy Proxy Middleware: Rotating IPs Without Bans
Build a Scrapy proxy middleware that rotates residential IPs per request. Includes retry logic, geo-targeting, bandwidth tracking, and ban detection.
6 min readWeb Scraping with Python Requests and Proxies: Complete Guide
How to configure proxies in Python's requests library, handle authentication, rotate IPs, manage sessions, and avoid the most common mistakes that get you blocked.
7 min readContinue exploring
Implementation guides for requests, Scrapy, Axios, Puppeteer, and more.
See how residential proxies fit large-scale scraping workflows.
Evaluate ProxyLabs against Bright Data, Oxylabs, Smartproxy, and others.
Browse location coverage and targeting options across 195+ countries.