Scrapy proxies: meta['proxy'], middleware order and rotation

Updated:

In Scrapy, a proxy is set per request through request.meta['proxy'] = 'http://user:pass@ip:port', and the built-in HttpProxyMiddleware (order 750) turns the user:pass part into a Proxy-Authorization header. Add a small downloader middleware that runs before it, at 740, and every request your spider yields can pick an IP from your ProxyV4 pool.

Scrapy · HTTP Proxy Format
request.meta['proxy'] = 'http://user:pass@ip:port'

Why the middleware number matters

Downloader middlewares run in ascending order on the way out. HttpProxyMiddleware at 750 reads meta['proxy'], strips the credentials from the URL and writes the auth header. If your own middleware sets the proxy afterwards, at 800 for example, the built-in one has already run, the credentials are never converted, and the proxy answers 407. Registering yours at 740 puts it first.

SettingSuggested valueEffect
request.meta['proxy']'http://user:pass@ip:port'Sends that request through the given ProxyV4 proxy
Your middleware order740Runs before HttpProxyMiddleware (750), so the login is encoded
CONCURRENT_REQUESTS_PER_IP2 to 4Limits parallel requests per destination IP, a polite cap on how hard each server is hit
AUTOTHROTTLE_ENABLEDTrueLets Scrapy stretch or shorten delays based on how fast the target responds

A rotation middleware in outline

  • Read the proxy list from settings in from_crawler() and keep it on the middleware instance
  • In process_request(), assign request.meta['proxy'] = random.choice(self.proxies) unless the request already carries one
  • When a response comes back 429 or 503, retry it with a different proxy from the pool instead of the one that was just refused
  • Combine DOWNLOAD_DELAY = 1.0 with RANDOMIZE_DOWNLOAD_DELAY = True so the gap between requests varies rather than ticking like a metronome

Sizing the pool

A Scrapy crawl can push a lot of requests per minute, so the number of IPs sets how gently each one is used. With ProxyV4 there is no minimum order and the price per IP drops as quantity rises, and private IPv4 traffic is not metered, so a large crawl costs the same as a small one on bandwidth. Each IP is used by one customer only, so its reputation reflects your own crawl and nobody else's. For planning crawl volume and politeness, see the web scraping guide.

Step by step

  1. 1

    Prepare the proxy URLs

    Convert your ProxyV4 ip:port:user:pass lines to http://user:pass@ip:port with the proxy format converter and store them in settings or a file.

  2. 2

    Write ProxyPoolMiddleware

    In middlewares.py, implement process_request(self, request, spider) so it sets request.meta['proxy'] = random.choice(self.proxies).

  3. 3

    Register it before the built-in one

    In settings.py, add 'myproject.middlewares.ProxyPoolMiddleware': 740 to DOWNLOADER_MIDDLEWARES and set CONCURRENT_REQUESTS_PER_IP = 2.

  4. 4

    Confirm rotation

    Fetch https://proxyv4.com/api/my-ip a few times with scrapy shell or a short test spider and check that the reported IP changes across your pool.

Frequently asked questions

My proxy middleware at priority 800 gets 407 errors. Why?

At 800 it runs after HttpProxyMiddleware (750), so the user:pass in your proxy URL is never turned into a Proxy-Authorization header. Move your middleware below 750, e.g. 740.

Can I set the proxy for just one request?

Yes. Pass meta={'proxy': 'http://user:pass@ip:port'} when you create the Request; the built-in middleware handles the login for that request only.

Will a crawl of millions of pages hit a bandwidth limit?

Not on ProxyV4 private IPv4 or static ISP proxies; both have unlimited bandwidth. The practical limit is how fast the target lets you crawl.

Unmetered static IPs for Scrapy crawls

Private IPv4 in 7 countries plus static ISP in the US and Vietnam, from a single IP to a large pool, with live volume pricing.

Check live US prices

Related articles

Proxies by platform
Proxies for web scraping: a fixed pool of IPs with unmetered traffic
Web scraping proxies for Python, Scrapy, Playwright and Selenium: a pool of private IPv4 and static ISP addresses, unlimited bandwidth, flat per-IP pricing.
Proxy setup
Python requests through an authenticated proxy, step by step
Send Python requests through an authenticated HTTP(S) proxy: build the proxies dict, attach it to a Session, encode odd passwords, rotate a list, check the IP.
Proxy setup
Playwright proxy authentication, one static IP per context
Give each Playwright browser context its own authenticated HTTP(S) proxy in Node.js or Python, match timezone and locale to the IP and confirm the exit address.
Free tools
Rewrite a proxy list into the format your tool expects
Convert proxy lists in your browser between ip:port:user:pass, user:pass@ip:port, http:// URLs, SOCKS5 URIs, JSON arrays and FoxyProxy import files, in bulk.
Proxies by platform
Proxies for SEO rank tracking: see the results page a local searcher sees
SEO rank tracking proxies with a private IPv4 in the US, UK, Vietnam, Japan and four more markets, so rankings, local packs and ads match what locals see.
Proxies by platform
Amazon seller proxies that give each account a permanent address
Amazon seller proxies for Seller Central, KDP and Merch: a US static ISP or UK/Japan private IPv4 per account, rented to you alone and kept on renewal.
IPV4 · united states
Build a US IP Pool for Scraping, Rank Tracking and Ad Checks
Buy US private IPv4 proxies: static American datacenter IPs, one customer per IP, unlimited bandwidth. Built for scraping, SERP tracking and US ad checks.
IPV4 · united kingdom
A Dedicated British IP for UK Marketplaces, Search and Campaigns
UK private IPv4 proxy with a static British datacenter IP rented to one customer, for eBay UK and Amazon.co.uk research, google.co.uk tracking and UK ad checks.