Skip to content

Puppeteer proxy setup and authentication

Launch Chrome with --proxy-server=http://scale-us.netdash.io:2000 and call page.authenticate() with your netdash username and password before the first navigation.

Updated
Reading time
5 min
Checked against
6 sources

Puppeteer has no proxy field in its launch options, so a Puppeteer proxy setup has two parts. You pass Chrome's --proxy-server switch in args, with the scheme, host and port only, and you answer the gateway's authentication challenge with page.authenticate(). Call it on every page, before that page's first goto(). This page is one of the proxy integration guides.

netdash is an HTTP proxy. HTTPS sites go through a CONNECT tunnel, so the switch always uses http://, even when the pages you open use HTTPS.

Quick start: --proxy-server plus page.authenticate

launch.mjs
import puppeteer from "puppeteer";

const { NETDASH_USERNAME, NETDASH_PASSWORD } = process.env;
const browser = await puppeteer.launch({
  args: ["--proxy-server=http://scale-us.netdash.io:2000"],
});
try {
  const page = await browser.newPage();
  // Authenticate before the first goto(), or the gateway answers with a 407
  await page.authenticate({ username: `${NETDASH_USERNAME}-cc-US`, password: NETDASH_PASSWORD });
  await page.goto("https://api.ipify.org?format=json", { timeout: 30_000 });
  console.log(await page.evaluate(() => document.body.innerText));
} finally {
  await browser.close();
}
Checked against a local test proxy

Run it as an ES module (.mjs, or "type": "module" in package.json) with NETDASH_USERNAME and NETDASH_PASSWORD set. It prints the exit IP as JSON, for example {"ip":"203.0.113.10"}. Keep both values in a .env file or your secret manager, never in source control or in a chat with an assistant. If you don't have credentials yet, start with the quickstart.

Puppeteer proxy authentication

Puppeteer's BrowserContextOptions reference describes the split: proxyServer is the server with an optional port, and the username and password are set with page.authenticate(). The --proxy-server switch follows the same pattern: it carries http://scale-us.netdash.io:2000 and nothing else, and the credentials go to the page.

The username carries the netdash parameters:

ModeusernameExit IP
RotatingUSERNAME-cc-USNot pinned; the gateway assigns exit IPs
StickyUSERNAME-cc-DE-session-a1b2c3d4-ttl-30Same session ID, same exit IP for the 30-minute TTL while that IP stays available

The password is the proxy password shown in the dashboard (not your sign-in password), the same for every residential and mobile plan. The proxy format reference lists every host, port and parameter.

Two details from Puppeteer's page.authenticate() reference matter in practice. To answer the challenge, Puppeteer turns on request interception behind the scenes, which its docs say might affect performance. And passing null turns authentication off again for that page.

A proxy per browser context

browser.createBrowserContext() takes a proxyServer (and a proxyBypassList) for that context only. One browser can then run contexts with different exit countries or sessions, and each context keeps its own cookies and cache. Credentials still come from page.authenticate() on every page in the context.

This example opens a context with a sticky session in Germany through the Europe gateway. Puppeteer's docs don't say whether a context proxy also needs a launch-level --proxy-server; in our check (Puppeteer 25.13, Chrome 155) it didn't: a browser launched without the switch sent the context's requests and HTTPS tunnels to the gateway with the page's credentials.

context.mjs
import { randomBytes } from "node:crypto";
import puppeteer from "puppeteer";

const { NETDASH_USERNAME, NETDASH_PASSWORD } = process.env;
const sessionId = randomBytes(4).toString("hex"); // 8 characters, letters and digits

const browser = await puppeteer.launch();
try {
  // Its own proxy server, cookies and cache
  const context = await browser.createBrowserContext({
    proxyServer: "http://scale-eu.netdash.io:2000",
  });
  const page = await context.newPage();
  await page.authenticate({
    username: `${NETDASH_USERNAME}-cc-DE-session-${sessionId}-ttl-30`,
    password: NETDASH_PASSWORD,
  });
  page.setDefaultNavigationTimeout(30_000);
  await page.goto("https://api.ipify.org?format=json");
  console.log(await page.evaluate(() => document.body.innerText));
  await context.close();
} finally {
  await browser.close();
}
Checked against a local test proxy

Use GB for the United Kingdom, not UK, and pair exits in Europe with the -eu gateway. A new session ID starts a new sticky session; the sticky session syntax explains TTLs and the dashboard presets (15 minutes, 30 minutes, 12 hours, 7 days).

New tabs and popups

Credentials belong to a page, not to the browser. A tab opened by window.open() or by a link with target="_blank" is a new page without them. Puppeteer emits targetcreated on the browser for every new target in every context, and target.page() returns the page, or null for targets that aren't pages. Authenticate each new page there, with the same username, so popups stay in the same session as the page that opened them.

new-pages.mjs
import puppeteer from "puppeteer";

const { NETDASH_USERNAME, NETDASH_PASSWORD } = process.env;
const credentials = { username: `${NETDASH_USERNAME}-cc-US`, password: NETDASH_PASSWORD };

const browser = await puppeteer.launch({
  args: ["--proxy-server=http://scale-us.netdash.io:2000"],
});

// Register before anything opens new pages
browser.on("targetcreated", async (target) => {
  const page = await target.page(); // null for workers and other non-page targets
  if (page) await page.authenticate(credentials);
});

try {
  const page = await browser.newPage();
  await page.authenticate(credentials);
  await page.goto("https://api.ipify.org?format=json", { timeout: 30_000 });
  console.log(await page.evaluate(() => document.body.innerText));
} finally {
  await browser.close();
}
Checked against a local test proxy

A new page can start loading before the handler has run. If its first request fails with an authentication error, navigate it again after authenticate() has resolved.

Errors and fixes

SymptomCauseFix
net::ERR_INVALID_AUTH_CREDENTIALS, or a 407authenticate() called after goto(), a new tab without credentials, credentials written into --proxy-server, or a wrong passwordAuthenticate every page before its first navigation; keep the switch to http://host:port; copy the password from the dashboard
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; allow outbound TCP to the port (2000 for Scale)
net::ERR_TUNNEL_CONNECTION_FAILEDThe tunnel through the gateway couldn't be established. Start with the credentials: a wrong password, or a username outside the documented syntax (missing -cc-, UK instead of GB, a hyphen in the session ID)Send the same username and password through curl, as the troubleshooting guide shows; if curl succeeds, check the website and the timeout
Wrong exit countryA page authenticated with another country's username, or UK instead of GBOne username per context or task; use GB
Pages got slower after adding authenticate()Puppeteer answers the challenge with request interception, which its docs say might affect performanceExpected; don't add interception handlers you don't need

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

  • Playwright proxy setup

    Playwright takes username and password in its proxy option, per browser or per context.

  • Troubleshooting

    407 errors, connection failures, timeouts and the wrong exit country, with the cause of each.

  • Ad verification

    Check how ads and landing pages render for visitors in other countries.

Also useful: the Node.js guide for HTTP clients without a browser, 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. 01Puppeteer API: Page.authenticate()Accessed 2026-10-09
  2. 02Puppeteer API: BrowserContextOptions (proxyServer, proxyBypassList)Accessed 2026-10-09
  3. 03Puppeteer API: Browser.createBrowserContext()Accessed 2026-10-09
  4. 04Puppeteer API: LaunchOptions (args)Accessed 2026-10-09
  5. 05Puppeteer API: BrowserEvent (targetcreated)Accessed 2026-10-09
  6. 06Puppeteer API: Target (page(), type())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.