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
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();
}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:
| Mode | username | Exit IP |
|---|---|---|
| Rotating | USERNAME-cc-US | Not pinned; the gateway assigns exit IPs |
| Sticky | USERNAME-cc-DE-session-a1b2c3d4-ttl-30 | Same 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.
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();
}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.
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();
}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
| Symptom | Cause | Fix |
|---|---|---|
net::ERR_INVALID_AUTH_CREDENTIALS, or a 407 | authenticate() called after goto(), a new tab without credentials, credentials written into --proxy-server, or a wrong password | Authenticate every page before its first navigation; keep the switch to http://host:port; copy the password from the dashboard |
net::ERR_PROXY_CONNECTION_FAILED | Wrong host or port, or a firewall blocks outbound traffic to the gateway port | Copy the endpoint from the proxy format reference; allow outbound TCP to the port (2000 for Scale) |
net::ERR_TUNNEL_CONNECTION_FAILED | The 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 country | A page authenticated with another country's username, or UK instead of GB | One 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 performance | Expected; 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 supportSources
Third-party behaviour described on this page was checked against these documents.
- 01Puppeteer API: Page.authenticate()Accessed 2026-10-09
- 02Puppeteer API: BrowserContextOptions (proxyServer, proxyBypassList)Accessed 2026-10-09
- 03Puppeteer API: Browser.createBrowserContext()Accessed 2026-10-09
- 04Puppeteer API: LaunchOptions (args)Accessed 2026-10-09
- 05Puppeteer API: BrowserEvent (targetcreated)Accessed 2026-10-09
- 06Puppeteer API: Target (page(), type())Accessed 2026-10-09
Spotted something out of date? Tell us.