Integration · Crawling frameworks
How to use a proxy with Crawlee
Crawlee takes proxies through one object, ProxyConfiguration, and every crawler (Cheerio, Playwright, Puppeteer, HTTP) accepts it. Give it the ARC gateway as a URL with credentials and it rotates; give it a newUrlFunction that turns Crawlee's session id into an ARC _session- handle and each Crawlee session keeps its own exit IP.
Reviewed 30 Oct 2026
http://USERNAME _pool-arcfast _country-de:PASSWORD@ proxy.arcproxies.io:8000The short answer
proxyUrls: ['http://user:pass@host:port']is enough to start; the gateway does the rotating.newUrlFunction(sessionId)maps each Crawlee session to an ARC session handle, so the session pool and the exit IP move together.- When a session is retired after a 401, 403 or 429, the next session gets a new handle and therefore a new exit.
- The same
ProxyConfigurationworks forCheerioCrawler,PlaywrightCrawlerandPuppeteerCrawler; Crawlee handles browser proxy credentials for you.
Setup
Set up Crawlee with a proxy, step by step
- 01
Install Crawlee
This guide uses Crawlee 3 for Node. Add
playwrightonly if you usePlaywrightCrawler.shell2 linesnpm i crawleenpm i playwright # only for PlaywrightCrawler - 02
Rotating proxy in one line, and check the exit
One proxy URL with the rotating username: each new connection can leave from a different exit.
proxyInfoin the handler tells you which proxy a request used, which is the quickest way to confirm the config is live. The IP echo response confirms the exit itself.rotating.mjs15 linesimport { CheerioCrawler, ProxyConfiguration } from 'crawlee';const proxyConfiguration = new ProxyConfiguration({ proxyUrls: ['http://USERNAME_pool-arcfast_country-de:PASSWORD@proxy.arcproxies.io:8000'],});const crawler = new CheerioCrawler({ proxyConfiguration, additionalMimeTypes: ['application/json'], // let the echo response through async requestHandler({ request, json, proxyInfo }) { console.log(request.url, json?.ip ?? '', proxyInfo?.hostname); },});await crawler.run(['https://api.ipify.org?format=json']); - 03
A sticky exit IP per Crawlee session
newUrlFunctionreceives Crawlee's session id. Strip it to letters and digits and use it as the ARC handle: a session keeps its IP for_sesstime-minutes, and a retired session takes its IP with it.sticky.mjs21 linesimport { CheerioCrawler, ProxyConfiguration } from 'crawlee';const proxyConfiguration = new ProxyConfiguration({ newUrlFunction: (sessionId) => { // Crawlee ids look like "session_Ab12Cd34Ef"; keep [a-z0-9] for the handle. const handle = String(sessionId).replace(/[^a-z0-9]/gi, '').toLowerCase(); return `http://USERNAME_pool-arcfast_country-de_session-${handle}_sesstime-10:PASSWORD@proxy.arcproxies.io:8000`; },});const crawler = new CheerioCrawler({ proxyConfiguration, useSessionPool: true, // the default, shown for clarity persistCookiesPerSession: true, // cookies and IP stay together maxConcurrency: 10, async requestHandler({ $, request, session }) { console.log(session?.id, request.url, $('title').text()); },});await crawler.run(['https://example.com/category/1', 'https://example.com/category/2']); - 04
Choose the country per request
newUrlFunctionalso receives the request, so a country stored inuserDatacan pick the username. Country codes are lowercase ISO; each country here still gets a sticky handle per session.geo.mjs12 linesconst proxyConfiguration = new ProxyConfiguration({ newUrlFunction: (sessionId, { request } = {}) => { const country = request?.userData?.country ?? 'de'; const handle = String(sessionId).replace(/[^a-z0-9]/gi, '').toLowerCase(); return `http://USERNAME_pool-arcfast_country-${country}_session-${handle}_sesstime-10:PASSWORD@proxy.arcproxies.io:8000`; },});await crawler.run([ { url: 'https://example.com/fr/prices', userData: { country: 'fr' } }, { url: 'https://example.com/it/prices', userData: { country: 'it' } },]); - 05
Use the same config with PlaywrightCrawler
Browser crawlers take the same object. Crawlee passes the proxy, credentials included, to the browser it launches, so there is no
page.authenticate()to call.browser.mjs13 linesimport { PlaywrightCrawler } from 'crawlee';const crawler = new PlaywrightCrawler({ proxyConfiguration, // from the sticky example above maxConcurrency: 4, // browsers are heavier than HTTP requests maxRequestRetries: 3, async requestHandler({ page, request }) { console.log(request.url, await page.title()); }, failedRequestHandler({ request }, error) { console.error('gave up', request.url, error.message); },});
How Crawlee's session pool and ARC sessions fit together
Crawlee's session pool tracks a set of sessions, each with its own cookies and error score. With newUrlFunction mapping session id to _session- handle, each Crawlee session is also one ARC exit. Three defaults in Crawlee 3.18 matter:
| Setting | Default | What it means with ARC |
|---|---|---|
| Blocked status codes | 401, 403, 429 | The session is retired; its replacement mints a new handle, so the retry leaves from a new IP. |
maxRequestRetries | 3 | Ordinary failures (timeouts, 5xx) are retried up to three times. |
maxSessionRotations | 10 | Session rotations after blocks are counted separately from maxRequestRetries. |
That is the sticky session model with replacement built in. Sticky holds are best effort, so a session's IP can still change before _sesstime- ends; Crawlee treats the resulting error like any other and retries.
Concurrency and rate limits
maxConcurrency caps parallel requests across the crawler; maxRequestsPerMinute caps the rate. Start low per target domain and raise it while watching the 429 rate. More parallelism through more IPs does not change what a site considers reasonable, and its robots.txt and terms still apply. Handling 429 rate limits and the web scraping use case cover the pacing side.
Crawlee for Python and Crawlee 4
- Crawlee for Python has the same concept:
ProxyConfiguration(proxy_urls=['http://user:pass@host:port'])fromcrawlee.proxy_configuration, passed to the crawler'sproxy_configuration. - Crawlee 4 is a release candidate on npm at the time of writing and changes parts of the proxy API. The snippets here target Crawlee 3, the current
latestrelease.
The problem
Common pitfalls
Session ids used raw as handles
Crawlee's ids contain an underscore (session_…), and underscores separate tokens in the ARC username. Strip the id to letters and digits first, as in the examples.
Logging proxyInfo.url
proxyInfo.url contains the password. Log proxyInfo.hostname or the session id instead.
Browser concurrency set like HTTP concurrency
A maxConcurrency that is fine for CheerioCrawler can exhaust memory with PlaywrightCrawler, and every browser page also costs far more bandwidth than its HTML.
FAQ
Questions
Something not covered? Write to contact@arcproxies.io.
How do I add a proxy with a username and password to Crawlee?
Put the credentials in the proxy URL: new ProxyConfiguration({ proxyUrls: ['http://user:pass@host:port'] }), then pass it as proxyConfiguration to the crawler. Crawlee uses it for HTTP crawlers and passes it on to the browsers it launches.
How do I keep the same IP for a Crawlee session?
Use newUrlFunction(sessionId) and build the username from the session id, for example …_session-<id>_sesstime-10. Every request in that session then uses the same ARC session handle and the same exit IP.
How does Crawlee rotate proxies?
With proxyUrls, Crawlee picks a URL from the list per session. With a single ARC gateway URL, rotation happens at the gateway instead: a username without a _session- token can take a different exit on each new connection.
Can I use a different country per request in Crawlee?
Yes. newUrlFunction receives { request } as its second argument, so you can read a country from request.userData and put it in the _country- token of the username.
Sources & review
Last reviewed by the ARC Proxies team. Prices are read from the live catalog at build time.
- [1]Crawlee: Proxy management (JavaScript)
- [2]Crawlee: ProxyConfiguration API reference
- [3]Crawlee: Proxy management (Python)
Next
What people build with it
Integrations
Other crawling frameworks
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.