Docs menu
Docs

How to Use Proxies for Web Scraping

To use proxies for web scraping, point your scraper's HTTP client or browser at a rotating proxy gateway, let each independent request leave from a new IP, hold one sticky IP only where a site must see one visitor, and retry a blocked request on a new IP after a pause. Add a pace per site and a check that each response holds real content, and the proxy does the rest. With ProxyField the connection is one setting, gate.proxyfield.io:7000 with your username and password, and residential traffic costs from $1.95/GB; start with the Easy Trial: 1 GB for $2.95.

residential IPs
412M+
from, traffic never expires
$1.95/GB
Easy Trial
1 GB for $2.95
gate.proxyfield.io:7000
What you enter in your scraper
Scraper settingProxyField value
Hostgate.proxyfield.io
Port7000
ProtocolHTTP, HTTPS or SOCKS5, all 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
SOCKS5the same username and password; where a tool asks for a proxy URL, write socks5h:// so the gateway resolves the site's name
No passwordadd your server's IP to the allowlist (up to 100 IPv4 addresses) and use 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>: rotate for independent pages, hold one session for a flow or your own login
Threadsunlimited concurrent threads, so the pace per site is yours to set
Headersthe gateway adds no Via, X-Forwarded-For or Forwarded header; the headers your scraper sends pass through; your Proxy-Authorization is removed before the request goes to the site

Set up your scraper with ProxyField

  1. Test the login with one cURL request through the gateway.
  2. Put the proxy URL into your HTTP client or browser automation tool.
  3. Rotate per request for independent pages; hold a sticky session for a multi-step flow.
  4. Treat 403, 429, 503 and challenge pages as failures and retry on a new IP, 2 or 3 times at most.
  5. Start with 3-5 parallel requests per site and raise it while the success rate holds.

In Python requests the same settings are one proxy URL, used for both schemes.

Python
import requests

PROXY = "http://<login>-country-us-city-new_york:<password>@gate.proxyfield.io:7000"
r = requests.get("https://api.ipify.org", proxies={"http": PROXY, "https": PROXY}, timeout=30)

Requests' own guide to proxies: Advanced Usage (Requests documentation).

On this page 10 sections

What you need

For the proxy type to buy for scraping and the cost per page, see web scraping proxies. For the code, you need:

  • Proxy access: the gateway gate.proxyfield.io:7000 with a username and password, or your server's IP on the allowlist and the port you set up in the dashboard. Access opens once the payment is confirmed; both are in your account.
  • A location, if the site varies by country: written into the username, as in <login>-country-us-city-new_york. ProxyField has 412M+ residential IPs in 195+ countries, with targeting by country, region (state) and city (proxy location targeting).
  • A scraper: any HTTP client or browser automation tool that accepts a proxy. The gateway speaks HTTP, HTTPS and SOCKS5; the examples below use HTTP with a username and password.

Step 1. Test the connection

Send one request through the proxy before you touch the scraper:

Shell
curl -x gate.proxyfield.io:7000 -U "<login>-country-us-city-new_york:<password>" https://api.ipify.org

The IP it prints should not be yours. Run it twice: on a rotating gateway the 2 IPs differ. A 407 means the username or password is wrong (407 proxy authentication required).

Step 2. Put the proxy into your scraper

The proxy goes wherever your code opens connections.

Python requests

Python
import requests

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

r = requests.get("https://example.com/products?page=1", proxies=PROXIES, timeout=30)
print(r.status_code, len(r.text))

Scrapy: set the proxy per request; Scrapy's built-in proxy middleware reads the credentials from the URL.

Python
import scrapy

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

class ProductsSpider(scrapy.Spider):
    name = "products"
    start_urls = ["https://example.com/products?page=1"]

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url, meta={"proxy": PROXY})

    def parse(self, response):
        for title in response.css(".product-card h2::text").getall():
            yield {"title": title.strip()}

Node.js (fetch with undici)

JavaScript
import { fetch, ProxyAgent } from "undici";

const proxy = new ProxyAgent({
  uri: "http://gate.proxyfield.io:7000",
  token: "Basic " + Buffer.from("<login>-country-us-city-new_york:<password>").toString("base64"),
});

const res = await fetch("https://example.com/products?page=1", { dispatcher: proxy });
console.log(res.status, (await res.text()).length);

Headless browsers take the proxy at launch: see Playwright, Puppeteer and Selenium. More libraries: Python, Scrapy, Node.js, cURL.

Step 3. Decide how IPs change

The jobSessionWhy
Independent pages: product pages, search results, listingsA new IP on every requestSpreads the load over the pool; one block costs one request
A flow on one site: search → filter → page 2 → detailsOne sticky IP for the flowThe site sees one visitor; cookies and IP stay consistent
Pages behind your own loginOne sticky IP for the whole sessionA login that jumps between IPs looks like a stolen session

Use logins only for your own account and for data you are allowed to access; the acceptable use policy does not allow access to data behind logins you are not entitled to. Scraping behind a login is allowed only for data you are entitled to and the site's terms allow.

ProxyField holds a sticky session from 30 seconds to 36 hours (presets 1, 5, 10 and 30 minutes, 1, 3 and 6 hours). The username syntax for a session: -region-<region>, -session-<id> and -ttl-<seconds> (30 to 129,600 seconds, 20 minutes by default) after the location, as in <login>-country-us-region-new_york-city-new_york-session-he9f2qga-ttl-600.

One detail matters for per-request rotation: an HTTPS request travels inside a tunnel through the proxy, and requests that reuse one open tunnel may leave through the exit that opened it. If every request must get a new IP, open a new connection for each one (as requests.get without a Session does); reuse a Session when speed matters more than a new IP on every request. An open HTTPS connection keeps one exit IP until it closes.

Step 4. Detect blocks and retry on a new IP

A block does not always come as an error. Count a response as failed when:

  • the status is 403, 429 or 503;
  • the page is a challenge or "access denied" page, even with status 200;
  • the content you parse is missing (no title, no price, an empty list).

Then wait and try again; on a rotating gateway the next attempt leaves from a new IP. Stop after 2 or 3 attempts and log the URL, so a hard block does not eat your traffic in a loop. Honor Retry-After when the site sends it.

Python
import random
import re
import time
import requests

PROXY = "http://<login>-country-us-city-new_york:<password>@gate.proxyfield.io:7000"
PROXIES = {"http": PROXY, "https": PROXY}
BLOCK_MARKERS = ("captcha", "access denied", "unusual traffic", "verify you are human")

def looks_blocked(r):
    if r.status_code in (403, 429, 503):
        return True
    m = re.search(r"<title[^>]*>(.*?)</title>", r.text[:5000], re.I | re.S)
    title = m.group(1).lower() if m else ""
    return any(marker in title for marker in BLOCK_MARKERS)  # check the title, not the whole page

def fetch(url, attempts=3):
    for attempt in range(1, attempts + 1):
        wait = 2 ** attempt
        try:
            r = requests.get(url, proxies=PROXIES, timeout=30)
            if r.status_code == 200 and not looks_blocked(r):
                return r.text
            retry_after = r.headers.get("Retry-After", "")
            if retry_after.isdigit():
                wait = int(retry_after)
        except requests.RequestException:
            pass
        if attempt < attempts:
            time.sleep(wait + random.random())  # the next attempt gets a new IP
    return None  # log it and move on

What each status code means and how to fix it: 403 forbidden, 429 too many requests, and the full proxy errors guide.

Step 5. Set the pace

Rotation spreads requests over IPs, but sites also judge the total rate against them. ProxyField allows unlimited concurrent threads, so the limit is yours to set:

  1. Start with 3-5 parallel requests per website.
  2. Raise the number while the success rate holds and response times stay flat.
  3. Back off at the first 429 responses or when response times climb.
  4. Add a small random delay between requests to the same site.
Python
from concurrent.futures import ThreadPoolExecutor

urls = [f"https://example.com/products?page={n}" for n in range(1, 51)]
with ThreadPoolExecutor(max_workers=4) as pool:  # 4 parallel requests to this site
    pages = list(pool.map(fetch, urls))
print(sum(p is not None for p in pages), "of", len(urls), "pages fetched")

Step 6. Keep the rest of the request consistent

An IP is one signal of several. Send a current browser User-Agent with the headers that browser sends (Accept, Accept-Language), keep cookies within a sticky session and drop them when the IP changes, and match the Accept-Language to the exit country where it matters. A proxy cannot fix a scraper that announces itself in its headers: what proxies can and cannot fix.

Step 7. Measure success and traffic

Log, per site: requests sent, successes (by content, not status), retries and response times. Watch traffic in the dashboard, which shows usage in real time and the gigabytes left. If traffic runs ahead of your estimate, the usual causes are a browser loading whole pages and retries in a loop: block images, fonts and media you do not parse, and cap retries at 2 or 3.

Common mistakes

MistakeWhat happensFix
Rotating inside a login or a cartThe site sees the session jump between IPs and ends itOne sticky IP per session
Retrying without a limitA blocked page eats traffic in a loop2-3 attempts with a pause
Counting status 200 as successChallenge pages slip into your dataCheck the content you parse
Running every thread against one site429 responses, then blocksA per-site limit on parallel requests
Credentials in shared codeAnyone with the code can spend your trafficEnvironment variables, or an IP allowlist on fixed servers

Scrape public data, read each site's terms and robots.txt, and keep within our acceptable use policy; the legal side is in is web scraping legal.

How to Use Proxies for Web Scraping FAQ

How should retries work with proxy rotation?

ProxyField's rotating gateway gives a new IP on every request, from $1.95/GB, so a retry leaves from a new IP without extra code. Treat 403, 429, 503 and challenge pages as failures, wait a few seconds (or as long as Retry-After says), and retry. Stop after 2 or 3 attempts and log the URL instead of looping.

How many requests per IP is too many?

It depends on the site: some tolerate dozens of requests a minute from one IP, others react after a few. With per-request rotation you rarely reach any limit on one IP; what sites notice is your total rate, so cap parallel requests per site and back off at the first 429.

How do I know if a website has blocked my scraper?

Look for 403, 429 or 503 responses, challenge or "access denied" pages, and pages served with status 200 that lack the content you parse. A sudden drop in the share of pages with real content is the clearest sign.

How do you calculate the proxy concurrency you need?

Start with 3-5 parallel requests per website, raise it while the success rate holds and response times stay flat, and back off when 429 responses appear. ProxyField threads are unlimited, so the right number is set by each site, not by the proxy.

Should the IP rotate on every request when scraping with a browser?

Only when each page load is independent. A browser that moves through a site, keeps cookies or signs in should hold one sticky IP for the whole visit, because a page whose resources arrive from changing IPs looks odd to the site.

Do I need to change headers when I rotate proxies?

Keep the headers of one real browser and send them consistently; you do not need new headers for every IP. Do clear cookies when the IP changes, and keep cookies and IP together within a sticky session.

How many requests should a proxy trial include?

Enough to count: 200-500 requests per target site, sent with the headers and concurrency you plan to use, and checked for real content. At 100 KB per HTML page that is 20-50 MB, so a 1 GB trial covers several targets and countries.

When should a proxy request be retried?

Retry timeouts, connection errors, 429 and 503 responses, and pages that come back without the content you expected; wait first, and honor Retry-After when the site sends it. Do not retry 404 or other answers that will not change, and fix a 407 (wrong proxy credentials) instead of retrying it.

How do you control proxy concurrency at scale?

Set a limit of parallel requests per site rather than one global number: too many at once to one site bring 429 Too Many Requests responses, slowdowns or challenge pages, often for a while after you slow down. Rotation spreads requests over IPs but not your total rate, so raise each site's limit only while its success rate holds.

Easy Trial: 1 GB for $2.95.

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