How to use proxies with Scrapy
In Scrapy, set the proxy per request with meta={"proxy": "http://USERNAME:PASSWORD@HOST:PORT"}. The built-in HttpProxyMiddleware reads the credentials from the URL and sends the Proxy-Authorization header for you.
What you need
- An active CleanProxies plan: static ISP proxies for fixed US IPs, or rotating residential / mobile proxies for pools. The trial works too.
- Your credential line from the dashboard's proxy manager: host (or IP), port, username and password.
- A Scrapy 2.x project (
pip install scrapy,scrapy startproject myproject).
New to proxies? For the overview, read Proxies with Python Requests, Playwright and Puppeteer and Best residential proxies for web scraping. This guide goes deeper on Scrapy only.
Your CleanProxies credentials
| Product | Line in your dashboard | Notes |
|---|---|---|
| Static ISP proxies | IP:PORT:USER:PASS | One line per dedicated IP. With IP whitelisting turned on, the line is just IP:PORT and no password is sent. |
| Rotating residential and mobile | HOST:PORT:USER:PASS | Generated in the proxy manager. The username carries the location and session you pick, so generate a new list to change them. |
Most tools want the same details as a URL: http://USERNAME:PASSWORD@HOST:PORT for HTTP(S) or socks5://USERNAME:PASSWORD@HOST:PORT for SOCKS5. The examples on this page use those placeholders; copy the host, port, username and password from your CleanProxies dashboard. To convert a whole list at once, paste it into the proxy list formatter.
How to set up CleanProxies in Scrapy
- 1
Copy your credentials
Take a rotating residential line, or export your ISP list, from the CleanProxies dashboard. - 2
Add the proxy to requests
Setmeta["proxy"]on eachRequest, or add a downloader middleware that does it for every request. - 3
Tune the crawl
Enable AutoThrottle, set sensible concurrency per domain and keep retries on. - 4
Check the exit IP
Run a one-off spider againsthttps://api.ipify.organd log the response body.
Set the proxy on a request
import scrapy
PROXY = "http://USERNAME:PASSWORD@HOST:PORT"
class IpCheckSpider(scrapy.Spider):
name = "ip_check"
async def start(self): # Scrapy 2.13+; use start_requests() on older versions
yield scrapy.Request("https://api.ipify.org", meta={"proxy": PROXY})
def parse(self, response):
self.logger.info("Exit IP: %s", response.text)Use the HTTP(S) form of your CleanProxies credentials: Scrapy's default download handlers don't speak SOCKS5. The middleware also honours http_proxy and https_proxy environment variables when no meta proxy is set.
Rotate an ISP proxy list with a middleware
A downloader middleware can assign a proxy to every request. Put it before the built-in HttpProxyMiddleware (priority 750) so the credentials are processed.
import random
class CleanProxiesMiddleware:
def __init__(self, proxies):
self.proxies = proxies
@classmethod
def from_crawler(cls, crawler):
path = crawler.settings.get("PROXY_LIST", "proxies.txt")
with open(path) as f:
lines = [line.strip() for line in f if line.strip()]
urls = []
for line in lines:
host, port, user, password = line.split(":", 3)
urls.append(f"http://{user}:{password}@{host}:{port}")
return cls(urls)
def process_request(self, request, spider):
request.meta.setdefault("proxy", random.choice(self.proxies))DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.CleanProxiesMiddleware": 740,
}
PROXY_LIST = "proxies.txt"
AUTOTHROTTLE_ENABLED = True
CONCURRENT_REQUESTS_PER_DOMAIN = 8
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]To keep one IP per logged-in account, store the chosen proxy with the account in meta and pass it along to follow-up requests instead of picking a new one.
SOCKS5 in Scrapy (experimental)
Recent Scrapy releases (2.17 and later) ship an experimental HTTPX-based download handler that accepts socks5:// proxy URLs in meta["proxy"]. Scrapy's docs flag it as not yet recommended for production, so HTTP(S) stays the default choice.
DOWNLOAD_HANDLERS = {
"http": "scrapy.core.downloader.handlers._httpx.HttpxDownloadHandler",
"https": "scrapy.core.downloader.handlers._httpx.HttpxDownloadHandler",
}
# then, per request:
# meta={"proxy": "socks5://USERNAME:PASSWORD@HOST:PORT"}Static ISP vs rotating residential in Scrapy
Static ISP proxies
The middleware above spreads requests over dedicated US ISP IPs with unlimited bandwidth. Retries can land on a different IP, which is what you want for public pages.
Rotating residential proxies
Point meta["proxy"] at one rotating residential line and each new connection gets a new IP from the 50M+ pool. For paginated flows that must stay on one IP, generate a sticky list and keep the same line for those requests.
Verify your exit IP
Run scrapy crawl ip_check. The log line Exit IP: … should show the proxy's address, not your server's.
Open What is my IP? through the proxy to see the address and headers a website receives, or paste up to ten lines into the free proxy checker to test connectivity, latency and exit IP before you start.
Troubleshooting Scrapy proxy errors
| Problem | Likely cause | Fix |
|---|---|---|
| 407 in the response or a TunnelError | Wrong credentials or a middleware that runs after HttpProxyMiddleware. | Copy the line again and give your middleware a priority below 750. |
| TCPTimedOutError / TimeoutError | Wrong port, blocked outbound traffic, or too much concurrency. | Test the line with curl -x; lower CONCURRENT_REQUESTS_PER_DOMAIN. |
| Lots of 403 or 429 responses | Too many requests per IP or a bot-detection layer on the target. | Enable AutoThrottle, add realistic headers, and switch to rotating residential IPs. |
| SOCKS5 URL fails | Scrapy's default download handlers have no SOCKS5 support. | Use the HTTP(S) proxy URL for the same credentials, or the experimental HTTPX download handler shown above. |
Still stuck? Our 24/7 support team answers fast: contact us with the error and the line you used (leave the password out).
Scrapy proxy FAQs
Yes. Put the username and password in the proxy URL in meta['proxy']; HttpProxyMiddleware strips them out and sends a Proxy-Authorization header.