Skip to content

Playwright proxy setup and authentication

Pass proxy: { server, username, password } when you launch the browser or create a context. Put the netdash username, with its country and session parameters, in username, not in the server URL.

Updated
Reading time
6 min
Checked against
7 sources

A Playwright proxy is a launch option or a context option, in the Node.js and Python APIs alike, and both forms accept a username and password. That is all netdash needs: no SDK, no extension, no local helper proxy. This page is one of the proxy integration guides and covers the Playwright library itself.

netdash is an HTTP proxy. HTTPS sites go through a CONNECT tunnel, so the server value always starts with http://, even when every page you open uses HTTPS.

Quick start (Node.js)

With Playwright and its Chromium build installed, this script opens a test page through the Americas gateway on the Scale plan and prints the exit IP:

import { chromium } from "playwright";

const browser = await chromium.launch({
  proxy: {
    server: "http://scale-us.netdash.io:2000",
    username: "USERNAME-cc-US",
    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();
Playwright

Example output

{"ip":"203.0.113.10"}

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

Syntax-checked

Replace USERNAME and PASSWORD with the credentials from the dashboard (Residential → Generate), or read them from the environment as the examples below do. The output is JSON with the exit IP, for example {"ip":"203.0.113.10"}. No account yet? The quickstart goes from sign-up to a first proxied request.

Playwright proxy authentication

The proxy option has four fields, and the netdash values go in like this:

Fieldnetdash valueNotes
serverhttp://scale-us.netdash.io:2000Scheme, host and port only. Use scale-eu.netdash.io:2000 for exits in Europe.
usernameUSERNAME-cc-US or USERNAME-cc-US-session-a1b2c3d4-ttl-30Your username plus the exit country and, for a sticky session, a session ID and TTL in minutes.
passwordThe proxy password from the dashboardNot your sign-in password. The same for every residential and mobile plan.
bypassOptional, for example localhost,127.0.0.1Hosts that bypass the proxy and connect directly, see below.

Playwright documents the credentials as separate username and password fields, so keep server to the scheme, host and port and don't write user:pass@ into it.

Proxy username

USERNAME-cc-US-session-a1b2c3d4-ttl-30

USERNAMEYour username
From the dashboard
-cc-USExit country
ISO code, GB for the UK
-session-a1b2c3d4Session ID
Sticky only; letters and digits
-ttl-30Lifetime
Minutes to keep the exit IP
Leave out -session-…-ttl-… for rotating sessions. The password is the proxy password from the dashboard, not your sign-in password.

httpCredentials is a different option. It answers HTTP authentication from the website itself (a 401 response), and Playwright's docs note that without an origin it sends the credentials to any server that asks. netdash authenticates at the proxy (a 407 response), so use proxy.username and proxy.password for netdash and keep httpCredentials for sites that need it. Every host, port and username parameter is listed in the proxy format reference.

Keep NETDASH_USERNAME and NETDASH_PASSWORD in a .env file or your secret manager, never in source control or in a chat with an assistant.

One proxy per browser context

A browser context is an isolated session with its own cookies and storage. Give each context its own proxy to run several exit countries or sessions in one browser. The script below opens two contexts through the Europe gateway: a sticky session in Germany and a rotating one in the United Kingdom. Use GB for the United Kingdom, not UK.

contexts.mjs
import { randomBytes } from "node:crypto";
import { chromium } from "playwright";

const { NETDASH_USERNAME, NETDASH_PASSWORD } = process.env;
const server = "http://scale-eu.netdash.io:2000"; // Europe gateway, Scale plan

const browser = await chromium.launch();
try {
  // Sticky: one session ID keeps one exit IP for the 30-minute TTL
  const sessionId = randomBytes(4).toString("hex"); // 8 characters, letters and digits
  const germany = await browser.newContext({
    proxy: {
      server,
      username: `${NETDASH_USERNAME}-cc-DE-session-${sessionId}-ttl-30`,
      password: NETDASH_PASSWORD,
    },
  });

  // Rotating: no session parameters
  const unitedKingdom = await browser.newContext({
    proxy: { server, username: `${NETDASH_USERNAME}-cc-GB`, password: NETDASH_PASSWORD },
  });

  for (const [country, context] of [["DE", germany], ["GB", unitedKingdom]]) {
    const page = await context.newPage();
    await page.goto("https://api.ipify.org?format=json", { timeout: 30_000 });
    console.log(country, await page.textContent("body"));
    await context.close();
  }
} finally {
  await browser.close();
}
Syntax-checked

Close a context when its task is done. Cookies set in one context never reach another, which keeps the two countries' sessions apart.

Sticky sessions for multi-step flows

Some flows span several pages: a language choice, a search, then the results pages. If the site ties that state to the visitor's IP address, keep the whole flow on one exit IP with a sticky session. Use one session ID for the context, and a new context with a new ID for the next run. Reusing a session ID keeps the same exit IP for the TTL while that IP stays available.

The TTL is in minutes. The dashboard presets are 15 minutes, 30 minutes, 12 hours and 7 days (-ttl-15, -ttl-30, -ttl-720, -ttl-10080); pick one longer than the flow. The sticky session syntax has the details.

sticky_flow.py
import asyncio
import os
import secrets

from playwright.async_api import Page, async_playwright


async def exit_ip(page: Page) -> str:
    await page.goto("https://api.ipify.org?format=json")
    return await page.text_content("body")


async def run_flow(urls: list) -> None:
    session_id = secrets.token_hex(4)  # 8 characters, letters and digits
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        context = await browser.new_context(proxy={
            "server": "http://scale-us.netdash.io:2000",
            "username": f"{os.environ['NETDASH_USERNAME']}-cc-US-session-{session_id}-ttl-30",
            "password": os.environ["NETDASH_PASSWORD"],
        })
        try:
            page = await context.new_page()
            page.set_default_navigation_timeout(30_000)
            print("start:", await exit_ip(page))
            for url in urls:
                await page.goto(url)
                print(url, await page.title())
                await asyncio.sleep(2)  # keep the pace gentle for the site
            print("end:  ", await exit_ip(page))  # same session, same exit IP
        finally:
            await context.close()
            await browser.close()


asyncio.run(run_flow(["https://example.com/", "https://example.com/about"]))
Syntax-checked

Python (sync API)

The sync API takes the same dictionary. Set at launch, the proxy covers the whole browser; set on new_context(), it covers that context.

launch.py
import os

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://scale-us.netdash.io:2000",
        "username": f"{os.environ['NETDASH_USERNAME']}-cc-US",
        "password": os.environ["NETDASH_PASSWORD"],
    })
    try:
        page = browser.new_page()
        page.goto("https://api.ipify.org?format=json", timeout=30_000)
        print(page.text_content("body"))
    finally:
        browser.close()
Syntax-checked

Playwright Test configuration

In Playwright Test, proxy is a use option, so you can set it once for the whole suite or per project. Projects per country run the same tests from three exit countries. Pair each with a matching locale, so the browser's language settings and the exit IP agree, which is what localization tests usually need.

Single proxy
import { defineConfig } from "@playwright/test";

export default defineConfig({
  use: {
    proxy: {
      server: "http://scale-us.netdash.io:2000",
      username: `${process.env.NETDASH_USERNAME}-cc-US`,
      password: process.env.NETDASH_PASSWORD,
      bypass: "localhost,127.0.0.1",
    },
    navigationTimeout: 30_000,
  },
});
Projects per country
import { defineConfig } from "@playwright/test";

// Exits in the Americas use the -us gateway, exits in Europe the -eu gateway.
const markets = [
  { country: "US", gateway: "scale-us.netdash.io:2000", locale: "en-US" },
  { country: "DE", gateway: "scale-eu.netdash.io:2000", locale: "de-DE" },
  { country: "GB", gateway: "scale-eu.netdash.io:2000", locale: "en-GB" },
];

export default defineConfig({
  use: { navigationTimeout: 30_000 },
  projects: markets.map(({ country, gateway, locale }) => ({
    name: country,
    use: {
      locale,
      proxy: {
        server: `http://${gateway}`,
        username: `${process.env.NETDASH_USERNAME}-cc-${country}`,
        password: process.env.NETDASH_PASSWORD,
        bypass: "localhost,127.0.0.1",
      },
    },
  })),
});
Syntax-checked

Run one market with npx playwright test --project=DE, or all three with npx playwright test.

Keep local services off the proxy

The bypass field lists hosts that bypass the proxy and connect directly, separated by commas. Add the app under test on localhost, a staging host you operate, or anything else that doesn't need an exit country: the gateway can't reach localhost or hosts on your private network, and direct traffic doesn't count against your balance. For example: bypass: "localhost,127.0.0.1,staging.example.com".

Using Playwright from an AI agent

Playwright MCP lets coding agents drive a Playwright browser. Its --proxy-server flag takes only a server address, so the credentials go in a config file: see Claude Code with Playwright MCP. For Browser Use, the OpenAI Agents SDK and LangChain, see the agent frameworks guide.

Errors and fixes

SymptomCauseFix
net::ERR_PROXY_CONNECTION_FAILEDWrong host or port, or a firewall blocks outbound traffic to the gateway portCopy the endpoint from the proxy format reference and allow outbound TCP to the port (2000 for Scale)
net::ERR_TUNNEL_CONNECTION_FAILED, or a 407Credentials written into server, a wrong password, or a malformed usernameMove the credentials to username and password; check the -cc- and session parameters
Navigation timeoutNo timeout set, or a page that takes longer than the timeoutSet timeout on goto() or navigationTimeout; check the gateway region too: pair US with -us and DE or GB with -eu
Wrong exit countryA context reused for another country, or UK instead of GBCreate one context per country; use GB
Requests to a local or staging server fail in testsThey went through the proxy, and the gateway can't reach that hostAdd the host to bypass, so its traffic skips the proxy

netdash forwards your traffic unchanged. It doesn't solve CAPTCHAs, render JavaScript or retry requests. Targeting is country-level.

Use it responsibly

Respect robots.txt and each site's terms, keep request rates reasonable and back off when a site slows you down. Don't collect personal data without a lawful basis or open content behind logins or paywalls without authorization. netdash doesn't solve CAPTCHAs or bot challenges, and your scripts shouldn't try to get past them either: if a site rate-limits or challenges your requests, slow down, check its terms, or use its official API. Read how we expect netdash to be used.

Next steps

Also useful: the Selenium guide, browser automation with netdash and rotating and sticky sessions.

Stuck? See troubleshooting or email support with your username (without the password) and the error message.

Email support

Sources

Third-party behaviour described on this page was checked against these documents.

  1. 01Playwright docs: Network, HTTP proxyAccessed 2026-10-09
  2. 02Playwright API: browserType.launch(), proxy optionAccessed 2026-10-09
  3. 03Playwright API: browser.newContext(), proxy optionAccessed 2026-10-09
  4. 04Playwright API: browser.newContext(), httpCredentials optionAccessed 2026-10-09
  5. 05Playwright for Python: Network, HTTP proxyAccessed 2026-10-09
  6. 06Playwright for Python API: browser.new_context(), proxyAccessed 2026-10-09
  7. 07Playwright Test: use options (proxy, projects)Accessed 2026-10-09

Spotted something out of date? Tell us.

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.