15% off your first purchase with code WELCOME15, up to 25 GB.

See pricing

Integration · AI & workflow tools

How to use a proxy with Crawl4AI

Crawl4AI takes a proxy per crawl: pass ProxyConfig(server=…, username=…, password=…) as proxy_config on CrawlerRunConfig, and every page fetched with that config goes through it. Point server at the ARC gateway and put pool, country and session in the username; a new username in a new config gives a new exit, so one crawler instance can run several markets or sessions side by side.

Reviewed 30 Oct 2026

your proxy, as a URL
http://USERNAME_pool-arcfast_country-de:PASSWORD@proxy.arcproxies.io:8000

The short answer

  • Set the proxy on CrawlerRunConfig(proxy_config=…). The proxy argument on BrowserConfig is deprecated and prints a warning.
  • server is scheme, host and port; username and password are separate fields.
  • Crawl4AI drives Chromium, so use the http:// scheme: Chromium supports no authentication for SOCKS5 proxies.
  • A rejected password does not come back as a 407. In our run it ended in a 60-second navigation timeout, so check result.success and result.error_message.

Setup

Set up Crawl4AI with a proxy, step by step

  1. 01

    Install Crawl4AI and its browser

    crawl4ai-setup installs the Playwright Chromium build the crawler drives; crawl4ai-doctor checks the installation.

    shell
    pip install -U crawl4aicrawl4ai-setupcrawl4ai-doctor
  2. 02

    Crawl through the gateway and check the exit IP

    Build a ProxyConfig, attach it to the run config, and fetch an IP echo service. CacheMode.BYPASS stops Crawl4AI from answering from its own cache, which would hide whether the proxy was used.

    check_exit.py
    import asynciofrom crawl4ai import AsyncWebCrawler, BrowserConfig, CacheMode, CrawlerRunConfig, ProxyConfigPROXY = ProxyConfig(    server="http://proxy.arcproxies.io:8000",    username="USERNAME_pool-arcfast_country-de_session-k3f9a1x2_sesstime-10",    password="PASSWORD",)async def main():    run = CrawlerRunConfig(proxy_config=PROXY, cache_mode=CacheMode.BYPASS)    async with AsyncWebCrawler(config=BrowserConfig(headless=True)) as crawler:        result = await crawler.arun("https://api.ipify.org?format=json", config=run)        print(result.success, result.markdown)   # the exit IP, not your ownasyncio.run(main())
  3. 03

    One session handle per crawl task, matched locale

    Mint a new _session- handle for each task and reuse the same config for every URL in it, including arun_many(). Setting locale and timezone_id on the same run config makes the browser present itself like a visitor in the exit's city. City names come from the published list, lowercased with spaces removed.

    task.py
    import secretsfrom crawl4ai import CacheMode, CrawlerRunConfig, ProxyConfigBASE = "USERNAME_pool-arcfast_country-de"   # pool + country; city and session added per taskdef run_for_task(city: str, locale: str, timezone: str) -> CrawlerRunConfig:    handle = secrets.token_hex(4)             # new handle, new exit IP    return CrawlerRunConfig(        cache_mode=CacheMode.BYPASS,        locale=locale,        timezone_id=timezone,        proxy_config=ProxyConfig(            server="http://proxy.arcproxies.io:8000",            username=f"{BASE}_city-{city}_session-{handle}_sesstime-10",            password="PASSWORD",        ),    )async def crawl_task(crawler, urls):    config = run_for_task("berlin", "de-DE", "Europe/Berlin")    results = await crawler.arun_many(urls, config=config)   # one exit for all    return [(r.url, r.status_code) for r in results if r.success]
  4. 04

    Spread independent pages over several sessions

    For URLs that do not depend on each other, Crawl4AI's RoundRobinProxyStrategy cycles through a list of proxies per request. With one gateway, the list is the same server with different session handles.

    rotation.py
    import secretsfrom crawl4ai import CrawlerRunConfig, ProxyConfigfrom crawl4ai.proxy_strategy import RoundRobinProxyStrategyproxies = [    ProxyConfig(        server="http://proxy.arcproxies.io:8000",        username=f"USERNAME_pool-arcfast_country-de_session-{secrets.token_hex(4)}_sesstime-10",        password="PASSWORD",    )    for _ in range(4)]config = CrawlerRunConfig(proxy_rotation_strategy=RoundRobinProxyStrategy(proxies))# results = await crawler.arun_many(urls, config=config)
  5. 05

    Check every result, not only exceptions

    arun() returns a result object rather than raising. Treat success == False and 429 or 5xx status codes as retryable on a fresh handle, and stop after a few attempts. If every attempt times out, test the credentials with the exit-IP check above.

    retry.py
    import asyncioasync def fetch(crawler, url, attempts=3):    for attempt in range(attempts):        config = run_for_task("berlin", "de-DE", "Europe/Berlin")   # fresh handle        result = await crawler.arun(url, config=config)        if result.success and result.status_code not in (429, 500, 502, 503):            return result        print(f"attempt {attempt + 1}: {result.status_code} {result.error_message}")        await asyncio.sleep(5 * 2 ** attempt)    raise RuntimeError(f"gave up on {url}")

Where the proxy goes in Crawl4AI

SettingStatusUse it for
CrawlerRunConfig(proxy_config=…)Current, documentedEverything: per-task sessions, per-market runs
CrawlerRunConfig(proxy_rotation_strategy=…)Current, documentedIndependent URLs spread across several sessions
BrowserConfig(proxy_config=…)Older approachExisting code; move it to the run config
BrowserConfig(proxy="http://user:pass@…")Deprecated, warnsNothing new

ProxyConfig.from_string() also parses http://user:pass@host:port, but the explicit fields avoid URL-encoding mistakes when a password contains special characters.

Sticky sessions for LLM-ready crawls

Crawl4AI renders pages in a headless browser, and a single page load opens many connections. With a rotating username those connections can leave from different exits inside one visit. Use a sticky handle per task, as above, and a new handle for the next task.

Rendered crawls are heavier than plain HTTP fetches, and every script and image counts against a per-GB balance. How much bandwidth scraping uses gives the figures to plan with, and reducing proxy bandwidth lists what to switch off.

Which ARC pool to use with Crawl4AI

  • [Residential](/residential-proxies/) (arcfast, arcultra): the default for rendered crawls of consumer sites, with country and city targeting.
  • [ISP](/isp-proxies/) (arc): the lowest price per GB; ISP-registered addresses hosted in data centres, suited to large documentation or news crawls.
  • Both are billed per GB that never expires, so a crawl that runs once a month does not pay for idle time.

The problem

Common pitfalls

A SOCKS5 server URL

Chromium cannot authenticate to a SOCKS5 proxy, so socks5:// with a username fails. The gateway accepts HTTP on the same port with the same credentials; use http://.

Cached results that never touched the proxy

With caching enabled, a repeated URL can come from Crawl4AI's local cache. Use CacheMode.BYPASS while testing the proxy, so the result reflects a real fetch.

Tiny test pages flagged as failures

In our run, arun_many() marked the 13-character IP-echo body as unsuccessful while arun() accepted it. Use arun() for the exit-IP check and real pages for batch tests.

Waiting a minute for a credential error

A wrong password showed up as Page.goto: Timeout 60000ms exceeded. Lower page_timeout on the run config while testing, so a credential problem surfaces in seconds.

FAQ

Questions

Something not covered? Write to contact@arcproxies.io.

How do I set an authenticated proxy in Crawl4AI?

Create ProxyConfig(server="http://host:port", username="…", password="…") and pass it as proxy_config to CrawlerRunConfig. Every arun() or arun_many() call that uses that config goes through the proxy.

Is BrowserConfig(proxy=...) still supported in Crawl4AI?

It still works but is deprecated: Crawl4AI 0.9.5 converts it to a ProxyConfig and prints a warning. The documentation recommends setting the proxy on CrawlerRunConfig so each request describes its own network settings.

Can one Crawl4AI crawler use several proxy sessions at once?

Yes. The proxy belongs to the run config, so two run configs with different ARC usernames, for example two _session- handles or two countries, leave from different exits in the same crawler instance.

Does Crawl4AI support SOCKS5 proxies?

ProxyConfig.from_string() accepts socks5://host:port, but the browser Crawl4AI drives has no SOCKS5 authentication. For a gateway with a username and password, use the http:// form.

Sources & review

Last reviewed by the ARC Proxies team. Prices are read from the live catalog at build time.

  1. [1]Crawl4AI: Proxy & Security: proxy_config, ProxyConfig and rotation
  2. [2]Crawl4AI: Browser, Crawler & LLM config: CrawlerRunConfig parameters
  3. [3]Chromium: Proxy support in Chrome: SOCKSv5 authentication

Next

What people build with it

Use caseProxies for AI and LLM training-data collectionCollect public web text, images and product data at corpus scale from residential and ISP IPs, paid per gigabyte with no monthly commitment.Use caseProxies for web scraping and data collectionA second provider that just works — Scrapy, requests, Crawlee or Playwright, self-serve, no sales call, bandwidth that never expires.Use caseResidential proxies for AI agentsBring your own residential IPs to browser-use, Playwright, Crawl4AI, n8n and any MCP tool — one sticky session per task, billed per GB.GlossaryHeadless browserA headless browser is a real web browser engine running without a visible window and controlled by code instead of a person; it loads pages, executes JavaScript and builds the DOM like a normal browser, which makes it the tool for pages whose content only appears after scripts run.GuideHow much bandwidth scraping usesBandwidth per page for HTML-only and browser-rendered scraping, using HTTP Archive page-weight data, with a worked table for 100,000 pages.GuideHow to reduce proxy bandwidthCut proxy bandwidth by fetching HTML or JSON instead of rendering, blocking images and fonts, using compression, conditional requests and local caching.ProductResidentialReal consumer IPs in 185+ countries with city targeting, rotating or sticky, billed per gigabyte with no subscription and no expiry.ProductISPDatacentre-hosted addresses registered to consumer ISPs — our fastest pool and lowest price per GB, for monitors, price feeds and plain HTML at volume.Use caseProxies for AI and LLM training-data collectionCollect public web text, images and product data at corpus scale from residential and ISP IPs, paid per gigabyte with no monthly commitment.

Get started

Get credentials and paste them in.

Sign up, buy a gigabyte, generate a username in the dashboard. Code WELCOME15 takes 15% off your first purchase; bandwidth never expires.