Skip to content

Proxies for browser automation

Run Playwright, Puppeteer and Selenium through netdash with one sticky session per browser context, credentials passed the way each tool expects, and only the traffic you need.

Proxy URL, exit IP in Germany

http://USERNAME-cc-DE-session-a1b2c3d4-ttl-30:PASSWORD@scale-eu.netdash.io:2000
scale-eu.netdash.io:2000
Host and port pick the plan and the gateway.
USERNAME
Your account username from the dashboard. One pair works on every residential and mobile plan.
-cc-DE
The exit country, as a two-letter ISO code. Use GB for the United Kingdom.
-session-a1b2c3d4-ttl-30
Keeps one exit IP for 30 min while that IP stays available.
  • Server and credentials as separate fields
  • Sticky sessions per context
  • No per-account concurrency limit

Where browser fleets go wrong with a proxy

A browser behind a proxy fails in a few predictable ways, and most of them have nothing to do with the website. The proxy gets the credentials in the wrong place, one exit has to serve tests that need several, or the browser spends much of its traffic on files no test looks at.

Each of these has a fix in how you configure the browser, which the rest of this page walks through.

  • Credentials in the proxy URL: Chromium-based browsers don’t read a username and password from the proxy server URL, so the gateway answers 407 Proxy Authentication Required
  • One proxy for the whole browser when a test suite needs several countries or sessions
  • The exit IP changing mid-test while the cookies stay, so the site sees one session arrive from two addresses
  • GB spent on images, video and fonts that no test inspects

Why each browser context needs its own exit

CI runners and containers usually sit in one or two cloud regions. Tests and workflows that depend on the visitor’s country, such as language, currency or consent banners, need an exit in that country, and when one run covers several countries, each browser context needs its own.

A context’s exit IP should also stay stable for as long as its cookies matter. A sticky session with a TTL longer than the job keeps the two together; a new context gets a new session ID and starts clean. For country-by-country checks of your own site, see localization testing.

From one browser to many contexts

  1. Step 1: Choose the proxy scope

    Per browser when every page in the run shares one exit; per context when one browser process needs several countries or sessions.

  2. Step 2: Map sessions to contexts

    One session ID per context or worker, such as w3k9x2m1: the worker index plus a short run hash, letters and digits only. Pick a TTL longer than the job, 30 or 720.

    Sessions and TTLs
  3. Step 3: Pass credentials as fields

    Server http://scale-eu.netdash.io:2000, with the username and password in their own fields, never inside the server URL.

    Proxy string format
  4. Step 4: Cut the traffic

    Abort image, media and font requests unless the test needs them, and send hosts you operate directly.

  5. Step 5: Confirm the exit

    Open https://api.ipify.org?format=json in each context and log the IP with the worker ID.

  6. Step 6: Handle failures by type

    Retry network errors with a new session ID; stop when the site limits you. The table further down maps symptoms to causes.

How each tool takes a proxy

Where the proxy and its credentials go in each tool, and whether one process can use several exits.

How each tool takes a proxy
AttributeWhere the proxy is setHow credentials are passedSeparate exits in one processGuide
Playwrightchromium.launch({ proxy }) or browser.newContext({ proxy })username and password fields next to serverYes, one per browser contextPlaywright guide
Puppeteer--proxy-server launch argument, or proxyServer in browser.createBrowserContext()page.authenticate({ username, password }) on each pageYes, one per browser contextPuppeteer guide
SeleniumThe proxy setting in the browser options when the driver session startsChrome doesn’t read them from the proxy URL; the guide shows how to supply themOne per driver sessionSelenium guide
Cloud browsersThe provider’s own proxy settingDepends on the providerDepends on the providerCloud browser guide

Based on each tool’s official documentation, checked on 2026-10-09.

Session layout for a parallel run

A runner in Europe collecting German pages. The examples use the Scale plan; every residential plan uses the same syntax, and you switch plans by changing the host and port.

Plan and endpoint

Scale: scale-eu.netdash.io:2000

The Europe gateway, for exits in Europe such as Germany.

Exit country

Per context: -cc-DE in the example

Each context in one browser can use a different country. Targeting is country-level.

Session mode and TTL

Sticky, -ttl-30 per context; 720 (12 h) for long jobs in one context

The exit IP stays the same for the TTL while that IP stays available. Pick a TTL that covers the time the context’s cookies are in use.

Session ID

Worker index plus a short run hash, for example w3k9x2m1

Unique per context. Letters and digits only, no hyphens.

Parallelism

One context per worker; add workers as needed

There is no per-account concurrency limit. Keep each site’s request rate reasonable.

Traffic

Abort image, media and font requests

Fewer GB per page. Keep them when a test checks visuals.

Hosts you operate

bypass in Playwright, proxyBypassList in Puppeteer

Staging servers and asset hosts you run don’t need an exit IP.

Build the connection for one context

Pick the plan, gateway, country and TTL, then copy the server and username into the context’s proxy fields.

Your route

Through the AshburnFrankfurt gateway to an exit IP in Via Ashburn (-us)United StatesCanadaMexicoBrazilArgentinaChileVia Frankfurt (-eu)United KingdomGermanyFranceSouth AfricaIndiaJapan, rotatingsticky for 15 minsticky for 30 minsticky for 12 hsticky for 7 days, on the ScaleMobile plan.

Proxy URL

http://USERNAME-cc-DE-session-a1b2c3d4-ttl-30:PASSWORD@scale-eu.netdash.io:2000

Replace USERNAME and PASSWORD with the credentials from your dashboard.

Scale, Europe gateway, exit IP in Germany, sticky for 30 min.

curl --max-time 30 -x "http://USERNAME-cc-DE-session-a1b2c3d4-ttl-30:PASSWORD@scale-eu.netdash.io:2000" \
  "https://api.ipify.org?format=json"
import requests

proxy = "http://USERNAME-cc-DE-session-a1b2c3d4-ttl-30:PASSWORD@scale-eu.netdash.io:2000"
proxies = {"http": proxy, "https": proxy}  # set both, or HTTPS requests bypass the proxy

response = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=30)
response.raise_for_status()
print(response.text)
import { ProxyAgent, fetch } from "undici";

const dispatcher = new ProxyAgent({
  uri: "http://scale-eu.netdash.io:2000",
  token: "Basic " + Buffer.from("USERNAME-cc-DE-session-a1b2c3d4-ttl-30:PASSWORD").toString("base64"),
});

const res = await fetch("https://api.ipify.org?format=json", { dispatcher, signal: AbortSignal.timeout(30_000) });
console.log(await res.text());
import { chromium } from "playwright";

const browser = await chromium.launch({
  proxy: {
    server: "http://scale-eu.netdash.io:2000",
    username: "USERNAME-cc-DE-session-a1b2c3d4-ttl-30",
    password: "PASSWORD",
  },
});
const page = await browser.newPage();
await page.goto("https://api.ipify.org?format=json");
console.log(await page.textContent("body"));
await browser.close();
{"ip":"203.0.113.10"}

Your output shows a different address in the country you chose.

Illustrative routes, not live traffic. Exits are available in most countries; the countries shown are examples. For exits in Oceania, ask support which gateway to use.All locations

Per-context sessions with assets skipped

Both examples give each browser context its own sticky session on the Europe gateway, skip images, media and fonts, and send staging.example.com directly. Playwright takes the credentials in the context’s proxy settings; Puppeteer sets the proxy on the context and the credentials on each page.

Swap the test URL for your own pages, and keep the session ID unique per context so parallel workers never share a session.

  • The server URL carries no credentials, so Chromium never has to read them from it
  • Puppeteer stalls intercepted requests until they are continued or aborted, so the handler always does one or the other
  • Navigation timeouts of 30 seconds
  • Syntax-checked; the API calls follow the current Playwright and Puppeteer documentation
import { chromium } from "playwright";

const SKIP = new Set(["image", "media", "font"]);
const RUN = Date.now().toString(36).slice(-6); // short run hash: letters and digits

// One context per worker: its own sticky session, exit IP and cookies.
async function contextFor(browser, worker, country = "DE") {
  const context = await browser.newContext({
    proxy: {
      server: "http://scale-eu.netdash.io:2000",
      username: `${process.env.NETDASH_USERNAME}-cc-${country}-session-w${worker}${RUN}-ttl-30`,
      password: process.env.NETDASH_PASSWORD,
      bypass: "staging.example.com", // hosts you operate don't need an exit IP
    },
  });
  await context.route("**/*", (route) =>
    SKIP.has(route.request().resourceType()) ? route.abort() : route.continue(),
  );
  return context;
}

const browser = await chromium.launch();
await Promise.all([0, 1, 2].map(async (worker) => {
  const context = await contextFor(browser, worker);
  const page = await context.newPage();
  await page.goto("https://api.ipify.org?format=json", { timeout: 30_000 });
  console.log(`worker ${worker}:`, await page.textContent("body"));
  await context.close();
}));
await browser.close();
Playwright
import puppeteer from "puppeteer";

const SKIP = new Set(["image", "media", "font"]);

// One browser context per session; credentials go to page.authenticate().
async function pageFor(browser, sid, country = "DE") {
  const context = await browser.createBrowserContext({
    proxyServer: "http://scale-eu.netdash.io:2000",
    proxyBypassList: ["staging.example.com"],
  });
  const page = await context.newPage();
  await page.authenticate({
    username: `${process.env.NETDASH_USERNAME}-cc-${country}-session-${sid}-ttl-30`,
    password: process.env.NETDASH_PASSWORD,
  });
  await page.setRequestInterception(true);
  page.on("request", (request) => {
    if (request.isInterceptResolutionHandled()) return;
    if (SKIP.has(request.resourceType())) request.abort();
    else request.continue();
  });
  page.setDefaultNavigationTimeout(30_000);
  return page;
}

const browser = await puppeteer.launch();
const page = await pageFor(browser, "w0k9x2m1");
await page.goto("https://api.ipify.org?format=json");
console.log(await page.$eval("body", (el) => el.textContent));
await browser.close();
Puppeteer

Spend GB on pages, not assets

You pay for the traffic that goes through the proxy, with no hidden multiplier. A browser downloads every image, font and video on a page, which often outweighs the HTML and data your test or workflow actually reads.

Three habits keep GB per page down. Measure a typical page in your own run, then price the total in the price calculator.

  • Abort resource types you don’t need: image, media, font
  • Send hosts you operate directly: list them in the tool’s setting for hosts that skip the proxy
  • Reuse a context for pages that share a session instead of opening a new one per page

Browser automation proxies: which product for which job

Residential suits most browser fleets. Static ISP and datacenter IPs are available through sales while self-serve checkout is paused.

  • Residential proxies

    Self-serve

    A country per context, sticky sessions sized to the job, and GB billing that suits bursty test runs.

    From $1.20/GB, graduated per order

  • ISP proxies

    Through sales

    Long-lived browser sessions that should keep one static IP across days.

    $1.60 per IP per 30 days

  • Datacenter proxies

    Through sales

    Steady browser jobs against systems you run, such as your staging or your own apps, where billing per IP suits the load.

    $1.40 per IP per 30 days

When a run fails

When a run fails
AttributeLikely causeWhat to do
407 Proxy Authentication RequiredWrong credentials, or the username syntax is offCheck the username and password fields; see troubleshooting
Requests leave without the proxyProxy set on the wrong object, or the host is listed to skip the proxyLog the exit IP per context; see troubleshooting
Timeout or connection resetA network problem between the browser, the gateway and the siteRetry with backoff and a new session ID
A CAPTCHA, a login wall or a 429 responseThe site is limiting youSlow down or stop. Don’t switch sessions to continue

Automate responsibly

Automate browsers against your own applications, or against public pages within each site’s terms and robots.txt. Keep request rates reasonable and stop when a site shows a CAPTCHA, a login wall or a rate limit: netdash doesn’t solve challenges, and switching sessions to continue is not how it’s meant to be used. More in how we expect netdash to be used.

Guides for each browser tool

Browser automation questions

Chromium-based browsers don’t read credentials from the proxy server URL. Pass them separately: Playwright’s username and password fields, Puppeteer’s page.authenticate(), and the method in the Selenium guide.

Per context when one browser process needs different countries or sessions; Playwright and Puppeteer both support it. Give each context its own session ID.

No. Your browser renders the page; netdash forwards its traffic unchanged.

Skip images, media and fonts you don’t need, send hosts you operate directly, and reuse contexts. You pay for the traffic that goes through the proxy; the calculator turns an estimate into a price.

ISP and datacenter static IPs exist, but self-serve checkout for them is paused. Contact sales with the locations and number of IPs you need.

Put your first context behind a proxy

Start with one context and one session ID, confirm its exit IP, then add workers. The Playwright guide covers launch-level and per-context proxies.

Privacy choices

We use cookies and similar technologies that this site needs to work and to remember your choice. We also use Google Analytics to understand which pages and features people use: in the EEA, the UK and Switzerland only with your consent. Live chat loads only if you open it. You can change your choice at any time under “Privacy choices” in the footer. Privacy Policy

Privacy choices

Choose what netdash.io may use. You can change this at any time under “Privacy choices” in the footer.

Necessary (always on)

Keeps the site working and secure, and remembers your privacy choices (nd_consent, 12 months).

In the EEA, the UK and Switzerland it stays off until you switch it on; elsewhere it is on unless you switch it off here. Google Analytics 4 measures page views, clicks on links and buttons, use of the price calculator, connection builder and code examples, scroll depth, file downloads, and page-performance metrics. It sets the cookies _ga and _ga_96MPNM6GHH, which last up to 12 months. Google processes this data, which may involve transfer to the United States. We do not send your name, email address or account details to Google Analytics. With this switched on we also remember a referral code or campaign you arrived with (nd_attr, 30 days), so a partner can be credited if you sign up.

Support chat (loads only when you open it)

Our live chat is provided by LiveChat. It loads only when you open the chat window. LiveChat then sets its own cookies and processes the messages you send and technical data about your browser.