Integrations menu
Developer guide

Scrapy Proxy Setup: Step by Step

To use a proxy in Scrapy, set it on each request with meta={"proxy": "http://<login>:<password>@gate.proxyfield.io:7000"}, or add a small downloader middleware that sets that meta key on every request; Scrapy's built-in HttpProxyMiddleware then sends the request through the proxy and passes the username and password. ProxyField residential proxies for Scrapy cost from $1.95/GB ($2.95/GB for 1 GB), with a 99.6% success rate, according to our service data, and the gateway gives you a new IP on every request. Start with the Easy Trial: 1 GB for $2.95, no subscription, and the traffic never expires.

residential IPs
412M+
from, traffic never expires
$1.95/GB
Easy Trial
1 GB for $2.95
gate.proxyfield.io:7000
What goes in a Scrapy project
Scrapy settingProxyField value
meta["proxy"]http://<login>-country-us-city-new_york:<password>@gate.proxyfield.io:7000; the gateway takes HTTP, HTTPS and SOCKS5 on the same host and port
Username<login>-country-us-city-new_york; the optional keys are -country-<cc>, -region-<region>, -city-<city>, -session-<id> and -ttl-<seconds> (30 to 129,600 s, 20 min when ttl is left out); add -mobile or -dc right after the login for mobile or rotating datacenter IPs (-dc takes the country only)
Passwordyour ProxyField password; HttpProxyMiddleware turns the login in the URL into a Proxy-Authorization header
SOCKS5Scrapy's downloader does not support SOCKS proxies, so use the HTTP URL above; other tools write socks5h:// with the same username and password
No passwordadd your server's IP to the allowlist (up to 100 IPv4 addresses), then http://gate.proxyfield.io:<port>, where <port> is the port you set up in the dashboard
IP behavioura new IP on every request, or one IP for 30 s to 36 h with -session-<id>-ttl-<seconds>, set per request in meta
Concurrencyunlimited concurrent threads at the gateway; pace requests for the target site
Headersthe gateway adds no Via, X-Forwarded-For or Forwarded header; the headers Scrapy sends pass through; your Proxy-Authorization is removed before the request goes to the site
Credentialsin your ProxyField account, with the allowlist and the configurator (it generates as many proxy lines as you need); the examples read them from environment variables

Set up Scrapy with ProxyField

  1. Put your ProxyField login and password in PROXY_USER and PROXY_PASS.
  2. Set meta={"proxy": PROXY} on a request; the built-in HttpProxyMiddleware sends it through the gateway.
  3. For the whole project, add a downloader middleware that sets meta["proxy"], ordered before HttpProxyMiddleware (750).
  4. Run a spider against https://api.ipify.org?format=json and check the IPs it logs.

One request through the gateway, with a New York exit IP.

Python
import scrapy

PROXY = "http://<login>-country-us-city-new_york:<password>@gate.proxyfield.io:7000"

class IpSpider(scrapy.Spider):
    name = "ip"

    def start_requests(self):
        yield scrapy.Request("https://api.ipify.org?format=json", meta={"proxy": PROXY})

    def parse(self, response):
        yield response.json()

Scrapy's own reference for the proxy middleware: Downloader Middleware: HttpProxyMiddleware (Scrapy docs).

Mobile 5G/4G proxies cost $3.45/GB for 1 GB down to $2.45/GB from 1,000 GB, on the same gateway and the same balance.

Written for Scrapy 2.11 or later; on Scrapy 2.13 and later the spider's entry point can also be written as async def start(self), and start_requests() below is the form older versions use.

On this page 10 sections

1. A proxy on one request

Python
import os
import scrapy

PROXY = f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}@gate.proxyfield.io:7000"


class IpSpider(scrapy.Spider):
    name = "ip"

    def start_requests(self):
        for _ in range(3):
            yield scrapy.Request("https://api.ipify.org?format=json", meta={"proxy": PROXY}, dont_filter=True)

    def parse(self, response):
        yield response.json()  # a different IP on each line

Run it with scrapy runspider ip_spider.py -o ips.json. HttpProxyMiddleware, on by default, reads meta["proxy"], turns the username and password in the URL into a Proxy-Authorization header, and opens an HTTPS tunnel for https:// URLs, so TLS runs from Scrapy to the site.

2. The proxy for the whole project

Rather than adding meta in every spider, set it once in a downloader middleware. In middlewares.py:

Python
class ProxyFieldMiddleware:
    def __init__(self, proxy):
        self.proxy = proxy

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler.settings.get("PROXYFIELD_URL"))

    def process_request(self, request, spider):
        request.meta.setdefault("proxy", self.proxy)  # a spider can still override it per request

In settings.py:

Python
import os

PROXYFIELD_URL = f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}@gate.proxyfield.io:7000"

DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.ProxyFieldMiddleware": 350,  # runs before HttpProxyMiddleware (750)
}

The number matters: your middleware must run before HttpProxyMiddleware, which handles the credentials. Replace myproject with your project's package name. A quicker option for a test: HttpProxyMiddleware also reads the http_proxy and https_proxy environment variables when the crawl starts.

3. Rotating residential proxies in Scrapy

Scrapy has no rotation of its own, and with ProxyField you don't need a rotation package or a list: the gateway gives a new IP on every request, so one proxy URL rotates on its own.

  • A new IP per request: the rotating username. Scrapy may reuse an open connection for several requests to the same site; if each request must get its own IP, check the IPs your spider logs, as in section 1. An open HTTPS connection keeps one exit IP until it closes.
  • One IP for a sequence (a login and the pages behind it): a sticky session in the username, 30 s to 36 h, set per request in meta. Region, session and session time go in the same username: -region-<region>, -session-<id> and -ttl-<seconds> (30 to 129,600 seconds, 20 minutes by default), as in <login>-country-us-region-new_york-city-new_york-session-he9f2qga-ttl-600; every part after the login is optional. Residential is the default; add -mobile after the login for mobile IPs: <login>-mobile-country-us.
  • Several countries: a proxy URL per country, picked per request:
Python
import os, random

def proxy_for(country):
    return f"http://{os.environ['PROXY_USER']}-country-{country}:{os.environ['PROXY_PASS']}@gate.proxyfield.io:7000"

# in a spider or middleware
request.meta["proxy"] = proxy_for(random.choice(["us", "gb", "de"]))

The -country- key follows the example <login>-country-us-city-new_york. Country keys outside the US: the two-letter country code in lowercase, as in -country-de.

When you change the proxy of a request, keep the credentials in the URL. Since Scrapy 2.6.2, HttpProxyMiddleware drops a stale Proxy-Authorization header when the proxy URL changes; on older versions, or if you set that header by hand, a rotated request can carry the previous login and fail with 407. Update Scrapy rather than managing the header yourself.

4. Pace and retries

The gateway accepts unlimited concurrent threads, so the limits to set are for the target site's sake:

Python
CONCURRENT_REQUESTS_PER_DOMAIN = 8
DOWNLOAD_DELAY = 0.5
AUTOTHROTTLE_ENABLED = True
RETRY_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]
DOWNLOAD_TIMEOUT = 60

Leave 403 out of RETRY_HTTP_CODES: it usually means the site refused the request, and repeating it unchanged rarely helps. A retried request on a rotating username goes out from a new IP. More on refusals: 403 Forbidden When Scraping Through a Proxy.

5. JavaScript pages: scrapy-playwright and Splash

scrapy-playwright renders pages in a real browser, which takes the proxy in its launch options (or per browser context):

Python
PLAYWRIGHT_LAUNCH_OPTIONS = {
    "proxy": {
        "server": "http://gate.proxyfield.io:7000",
        "username": os.environ["PROXY_USER"],
        "password": os.environ["PROXY_PASS"],
    }
}

Requests with meta={"playwright": True} then go through the proxy. For one IP per browser context, define contexts in PLAYWRIGHT_CONTEXTS, each with its own proxy, and pick one with meta["playwright_context"]. The same settings are explained for plain Playwright on Playwright proxy setup.

Splash takes the proxy as an argument of each render request:

Python
from scrapy_splash import SplashRequest

yield SplashRequest(url, self.parse, args={"wait": 1, "proxy": PROXY})

6. SOCKS5 and Scrapy

Scrapy's downloader does not support SOCKS proxies. Use the HTTP proxy URL above: ProxyField's gateway speaks HTTP, HTTPS and SOCKS5 on the same account, and HTTP covers everything Scrapy fetches. If another part of your stack needs SOCKS5, see SOCKS5 proxies.

Check and monitor the proxy

  1. Run the spider in section 1: each line should show an IP that is not your server's.
  2. Scrapy's stats at the end of a crawl count responses by status: watch downloader/response_status_count/407 (the login), /403 and /429 (the site) and retry/count.
  3. A 407 means the proxy did not accept the login: check the credentials, encode special characters with urllib.parse.quote, and update Scrapy if you rotate credentials.
  4. Timeouts point to the port or a firewall: allow outgoing port 7000.
  5. To test lines without a spider, use the proxy checker.

Gateway error messages: 407 Proxy Authentication Required for a wrong login or password, an IP not on the allowlist or a malformed location, 402 Payment Required when no traffic is left and 502 Bad Gateway when no exit could be connected; a restricted site gets no separate response, and a 403 comes from the site itself. Status codes are explained in proxy errors and HTTP Error 407 Proxy Authentication Required. Some site categories are restricted to protect the network, including financial and government services. Our 24/7 live chat helps with setup and integration.

Which proxies to use with Scrapy

What your spider doesProxyPrice
Crawl public pages at scaleRotating residentialfrom $1.95/GB
Check what mobile users seeMobile 5G/4Gfrom $2.45/GB ($3.45 for 1 GB)
Large crawls of sites that accept datacenter IPsDatacenter$0.29/GB down to $0.22/GB
Reach an API that allowlists one fixed IPDedicated ISPfrom $2.29 per IP per 30 days

If you would rather receive pages than run proxies, the Web Scraping API fetches any URL for $0.50 down to $0.20 per 1,000 successful results (plain HTTP) or $2.00 down to $1.00 with JS rendering, billed on successful results only, through Contact sales.

New to Scrapy? Start with Scrapy Tutorial: Build Your First Spider. For single requests outside a crawl, see Python requests. Use ProxyField for lawful work such as public web data collection, price and SEO monitoring and testing, within our acceptable use policy.

Get started

Start with the Easy Trial: 1 GB for $2.95, with no minimum purchase and no subscription. The traffic never expires and all purchases are final. See pricing per GB.

Scrapy Proxy Setup FAQ

How do I rotate residential proxies in Scrapy?

ProxyField rotates residential IPs for Scrapy at the gateway, from $1.95/GB ($2.95 for 1 GB): set meta["proxy"] = "http://<login>:<password>@gate.proxyfield.io:7000" on each request, or once in a downloader middleware, and every request gets a new IP. You don't need a proxy list or a rotation package.

How do I set up a proxy in Scrapy?

Add meta={"proxy": "http://<login>:<password>@gate.proxyfield.io:7000"} to a scrapy.Request. The built-in HttpProxyMiddleware routes the request through the proxy and sends the login from the URL.

How do I set one proxy for every request in a Scrapy project?

Write a downloader middleware whose process_request sets request.meta["proxy"], and enable it in DOWNLOADER_MIDDLEWARES with a number below 750, so it runs before HttpProxyMiddleware. For a quick test, the http_proxy and https_proxy environment variables work too.

What is the Scrapy proxy middleware?

HttpProxyMiddleware, a downloader middleware that is on by default. It reads the proxy from request.meta["proxy"] or the environment, adds the Proxy-Authorization header from the URL's credentials and sends the request through the proxy.

What type of proxy works best for Scrapy?

ProxyField rotating residential proxies, from $1.95/GB, suit most crawls of public pages. Datacenter proxies at $0.29 down to $0.22/GB suit sites that accept datacenter IPs, and mobile 5G/4G IPs suit pages that differ for phones.

Why use proxies with Scrapy?

A crawl sends many requests to one site, and sites limit requests per IP. Proxies spread the crawl over many IPs and let you fetch pages as visitors in another country see them.

Does Scrapy support SOCKS5 proxies?

No, Scrapy's downloader supports HTTP and HTTPS proxies only. Use ProxyField's HTTP proxy URL; it covers everything Scrapy fetches.

Does Scrapy support HTTP proxies with a username and password?

Yes. Put the credentials in the proxy URL, http://<login>:<password>@host:port, and HttpProxyMiddleware sends them in the Proxy-Authorization header. Encode special characters in the password.

How do I set a random proxy per request in Scrapy?

In a middleware or spider, set request.meta["proxy"] to a URL picked at random, for example one per country. With ProxyField's gateway, the same URL already gives a new IP on every request.

Do I need a rotating proxy middleware in Scrapy?

Not with a rotating gateway. Rotation packages manage a list of proxies and drop dead ones; ProxyField's gateway rotates IPs itself and moves traffic to the next node if one slows down.

Show 9 more questionsShow fewer questions

Why does Scrapy keep the old Proxy-Authorization header when I rotate proxies?

Older Scrapy versions kept the header when the proxy URL changed, so a rotated request carried the previous login. Scrapy 2.6.2 and later drop it when the proxy changes; update Scrapy and keep the credentials in the proxy URL.

What does a 407 response mean in a Scrapy log?

The proxy did not accept the login: a wrong username or password, special characters that need encoding, or a stale header after rotating credentials. Fix the credentials in the proxy URL and update Scrapy.

How do I check if a proxy is working in Scrapy?

Crawl https://api.ipify.org?format=json through the proxy a few times with dont_filter=True and look at the IPs; they should not be your server's. Then watch the 407, 403 and 429 counts in the crawl stats.

How do I monitor and optimize proxies in Scrapy?

Watch the response status counts and retry/count in Scrapy's stats, enable AutoThrottle, and set per-domain concurrency and a delay for each site. Rising 429s mean slow down; rising 407s mean check the login.

Why does Scrapy get blocked when curl from the same machine works?

Scrapy sends many requests quickly with its own headers, while a single curl request looks like a one-off. Slow the crawl down, send ordinary browser headers and keep to the site's limits; rotating IPs spread the load, but they don't make a refused request acceptable.

How do I use a proxy with scrapy-playwright?

Set PLAYWRIGHT_LAUNCH_OPTIONS = {"proxy": {"server": "http://gate.proxyfield.io:7000", "username": ..., "password": ...}}, or a proxy per context in PLAYWRIGHT_CONTEXTS. Requests with meta={"playwright": True} then use it.

How do I use a proxy with Splash?

Pass the proxy URL as the proxy argument of the render request, for example SplashRequest(url, args={"proxy": "http://<login>:<password>@gate.proxyfield.io:7000"}). Splash fetches the page and its resources through it.

Can I use free proxies with Scrapy?

You can, but free public proxies are slow, shared and often already blocked, so a crawl spends most of its time on errors and retries. ProxyField has no free proxies; the smallest purchase is 1 GB for $2.95.

What are Scrapy proxies?

Proxies a Scrapy crawl sends its requests through, set in request.meta["proxy"] or a middleware. Any HTTP proxy works; rotating residential ones suit crawls of sites that limit requests per IP.

Easy Trial: 1 GB for $2.95.

Try for the price of 1 GB, no subscription, traffic never expires.