IPRoyal Rotating Residential IP Proxy in Python

IPRoyal’s residential IP pool has 20M+ IPs—the trick is knowing how to use them. Sticky mode (30 min per IP) suits account login scenarios, while rotating mode (new IP per request) excels at web scraping, bulk registration, and anti-detection. This guide implements a complete rotating + retry solution in Python.
Two modes explained
| Mode | IP Switch Frequency | Use Case |
|---|---|---|
| Sticky | Rotate every 10/30 minutes | Account login, API calls, long-running quant sessions |
| Rotating | New IP on every request | Web scraping, bulk registration, anti-detection |
IPRoyal’s dashboard lets you generate credentials for both modes.
Rotating proxy credentials format
Log in to IPRoyal Dashboard → Residential → Generate → Select Rotating → You’ll get:
Proxy: gw.iproyal.com
Port: 12321
Username: YOUR_USER
Password: YOUR_PASS_country-us_session-rotate
session-rotate is key: every request pulls a fresh IP from the pool.
Python basics
import requests
proxy_url = "http://USER:[email protected]:12321"
proxies = {"http": proxy_url, "https": proxy_url}
for i in range(5):
r = requests.get("https://ipinfo.io/json", proxies=proxies, timeout=10)
print(f"Request {i+1}: {r.json()['ip']} ({r.json().get('city')})")
Expected output:
Request 1: 142.176.xx.xx (San Diego)
Request 2: 71.192.xx.xx (New York)
Request 3: 98.44.xx.xx (Austin)
Request 4: 24.128.xx.xx (Boston)
Request 5: 104.128.xx.xx (Chicago)
Every request uses a different residential IP—like real users from different locations hitting your target.
Real-world 1: Anti-scraping for crawlers
Large sites (Amazon pricing, Google search results) often block scrapers. Rotating IPs makes the target think you’re “many different users” rather than a bot.
import requests
import time
from urllib.parse import quote
proxy = "http://USER:[email protected]:12321"
PROXIES = {"http": proxy, "https": proxy}
def scrape_url(url, max_retries=3):
"""Retries automatically switch to a fresh IP"""
for attempt in range(max_retries):
try:
# session-rotate ensures each retry is a new IP
r = requests.get(url, proxies=PROXIES, timeout=15,
headers={"User-Agent": "Mozilla/5.0 ..."})
if r.status_code == 200:
return r.text
elif r.status_code in (403, 429, 503):
print(f" Blocked ({r.status_code}), rotating IP [attempt {attempt+1}]")
time.sleep(2)
continue
else:
print(f" HTTP {r.status_code}")
return None
except requests.Timeout:
print(f" Timeout, retrying [attempt {attempt+1}]")
time.sleep(3)
except requests.RequestException as e:
print(f" error: {e}")
time.sleep(2)
return None
# Example: scrape 100 URLs
urls = [f"https://example.com/product/{i}" for i in range(100)]
for u in urls:
html = scrape_url(u)
if html: process(html) # Your parsing logic
time.sleep(0.5) # Be gentle
Key insight: session-rotate gives each requests.get() call a new IP, so failed requests automatically retry with a different IP—no manual switching needed.
Real-world 2: Bypass geographic restrictions
Some sites only serve specific regions. IPRoyal supports country targeting:
# US IP
us_proxy = "http://USER:[email protected]:12321"
# Japan IP
jp_proxy = "http://USER:[email protected]:12321"
# UK IP
uk_proxy = "http://USER:[email protected]:12321"
def get_by_country(url, country="us"):
proxy_url = f"http://USER:PASS_country-{country}[email protected]:12321"
return requests.get(url, proxies={"http": proxy_url, "https": proxy_url}).text
# Scrape Netflix US vs. Japan content
html_us = get_by_country("https://netflix.com/browse", "us")
html_jp = get_by_country("https://netflix.com/browse", "jp")
Real-world 3: Bulk account registration
(Legal note: Ensure the target site’s ToS permits this. Common legitimate scenarios: registering multiple test accounts for your own service, or compliance testing)
import random
def register_account(email, password, country="us"):
proxy_url = f"http://USER:PASS_country-{country}[email protected]:12321"
PROXIES = {"http": proxy_url, "https": proxy_url}
# Simulate human behavior: random delays
time.sleep(random.uniform(2, 5))
# Visit signup page first (get CSRF token)
session = requests.Session()
session.proxies = PROXIES
session.headers["User-Agent"] = random_user_agent()
resp = session.get("https://target.com/register")
csrf = extract_csrf(resp.text)
time.sleep(random.uniform(3, 8)) # Simulate "form filling" time
resp = session.post("https://target.com/register", data={
"email": email,
"password": password,
"_csrf": csrf,
})
return resp.status_code == 200
# Bulk registration
emails = load_emails()
for email in emails:
success = register_account(email, "StrongPass123!", random.choice(["us", "gb", "ca"]))
print(f"{email}: {'✓' if success else '✗'}")
time.sleep(random.uniform(30, 120)) # Space out accounts
Real-world 4: Distribute quant strategy requests
Binance enforces per-IP rate limits. If your quant strategy hammers the API, rotating IPs spreads the load:
import random
PROXY_POOL = [
f"http://USER:[email protected]:12321",
f"http://USER:[email protected]:12321",
f"http://USER:[email protected]:12321",
]
def binance_request(path):
"""Distribute requests across regional residential IPs"""
proxy = random.choice(PROXY_POOL)
return requests.get(f"https://api.binance.com{path}",
proxies={"https": proxy}, timeout=5)
# Run concurrently; each request lands on a different region's fresh IP
Better retry pattern with tenacity
Manual retry logic is error-prone. Use the tenacity library:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(5), wait=wait_exponential(multiplier=1, min=2, max=30))
def scrape_with_retry(url):
r = requests.get(url, proxies=PROXIES, timeout=15)
r.raise_for_status() # 4xx/5xx triggers retry
return r.text
Automatic exponential backoff (2s, 4s, 8s, 16s, 30s), and session-rotate guarantees a fresh IP on each attempt.
Cost comparison
| Solution | Monthly (10GB traffic) | Reliability | IP Quality |
|---|---|---|---|
| IPRoyal Residential Rotating | $70 | ⭐⭐⭐⭐⭐ | Residential broadband |
| Bright Data | $300 | ⭐⭐⭐⭐⭐ | Residential broadband (pricier) |
| Free proxy lists | $0 | ⭐ | 95% dead |
| DIY VPS | $20-50 | ⭐⭐⭐ | Datacenter IP, easily blocked |
IPRoyal offers the best bang for buck, but watch bandwidth costs (charged per GB). Heavy image/video scraping burns through traffic fast—budget accordingly.
Takeaway
IPRoyal Rotating mode solves:
- Scraper blocking & detection
- Geographic restrictions
- Bulk operations
- API rate limit distribution
Python + session-rotate suffix = automatic IP rotation. Use tenacity for cleaner retry logic.
Ready to start?
→ IPRoyal offers pay-as-you-go pricing; prepay $5 to get going (20M+ residential IP pool)
Important notes:
- Respect target site ToS
- Add reasonable delays to crawlers—don’t DDoS their infrastructure
- Privacy: IPRoyal sees your request URLs but not the content; HTTPS is encrypted
Further reading: