To use a proxy with Puppeteer, pass the proxy endpoint to Chromium through the --proxy-server launch argument, create the page, and call page.authenticate() before navigation when the HTTP proxy requires a username and password. Verify the observed exit from inside that same page before starting the real workflow.
Scope: this tutorial covers one HTTP or HTTPS-tunneling proxy per browser process in Node.js. For generic Node clients and curl, use the multi-client proxy guide; for the full protocol distinction, use the Proxy Setup and Developer Guides hub.
Start Chromium with a proxy launch argument
Puppeteer passes additional browser flags through the args property documented in the official Puppeteer LaunchOptions reference. Keep the endpoint separate from credentials so error messages, process listings, and copied commands do not reveal a password.
import puppeteer from 'puppeteer';
const PROXY_HOST = 'HOST';
const PROXY_PORT = 'PORT';
const browser = await puppeteer.launch({
headless: true,
args: ['--proxy-server=' + 'http://' + PROXY_HOST + ':' + PROXY_PORT],
});
const page = await browser.newPage();
This launch argument applies at browser-process level. Opening another page in the same process does not create a different upstream proxy. If two workers must use different endpoints, launch two browser processes or use an architecture that explicitly supports per-context routing.
Add proxy authentication before the first navigation
The official page.authenticate() reference describes credential handling and notes that authentication enables request interception internally. Call it before page.goto(). Read secrets from a protected runtime store; do not commit them to a JavaScript file.
const PROXY_USER = 'USER';
const PROXY_PASSWORD = 'PASSWORD';
await page.authenticate({
username: PROXY_USER,
password: PROXY_PASSWORD,
});
A 407 response usually means the proxy was reached but rejected the presented proxy authentication. Check the assigned method, credential spelling, account status, and whether source-IP authorization is expected instead. The proxy authentication guide separates those models.
Perform exit verification inside Puppeteer
Use a trusted HTTPS endpoint that returns the requester’s address, then compare it with a direct baseline. Inspect status and content type before parsing the body; an HTML challenge page is not an IP result.
const response = await page.goto('https://api.ipify.org?format=json', {
waitUntil: 'domcontentloaded',
timeout: 30000,
});
if (!response || !response.ok()) {
throw new Error(`Exit check failed: ${response?.status() ?? 'no response'}`);
}
const observed = await page.evaluate(() => JSON.parse(document.body.innerText));
console.log({ exitIp: observed.ip });
Expected observation: the page reports the assigned proxy exit, HTTPS validation remains enabled, and a second request succeeds with the same endpoint when the plan is static. If the direct IP remains visible, stop and inspect the browser launch arguments rather than continuing the automation.
Design session isolation deliberately
Session isolation means keeping cookies, cache, credentials, and one intended egress together for the life of a workflow. Use a separate browser context for separate application sessions, but remember that contexts inside one Chromium process still inherit its process-level proxy.
const context = await browser.createBrowserContext();
const sessionPage = await context.newPage();
await sessionPage.authenticate({ username: PROXY_USER, password: PROXY_PASSWORD });
// Perform one authorized session, then close its context.
await context.close();
Do not rotate the address halfway through a login or transaction simply because a request failed. First classify the failure. Changing the egress can invalidate state and make a reproducible bug look intermittent.
Puppeteer troubleshooting by symptom
| Symptom | Likely boundary | First check |
|---|---|---|
ERR_PROXY_CONNECTION_FAILED |
Gateway DNS, port, route, or listener | Test the documented host and port once outside Puppeteer |
| 407 response | Authentication | Check method, credentials, and source-IP allowlist |
| Timeout after connection | Tunnel, TLS, or destination | Compare a known exit endpoint with the real target |
| Direct IP still visible | Launch configuration | Log the non-secret endpoint label and actual browser args |
| Only one website fails | Destination policy or application state | Preserve status and response class; do not retry blindly |
The layered sequence in Common Proxy Errors and Fixes helps separate connectivity, DNS, TLS, and destination responses.
Operational limits: run automation only on systems and accounts you are authorized to test, follow destination terms and rate limits, cap concurrency, and redact cookies, tokens, and proxy credentials from screenshots and logs. A proxy changes a route; it does not grant access.
Choose an endpoint after the Puppeteer test is reproducible
Record the required country, protocol, authentication method, session duration, browser count, and measured latency. If the workflow needs a stable exclusive egress, compare those requirements with the current private proxy options and start with a small controlled allocation.

