# Using proxies with Puppeteer and headless Chrome

Chrome takes the proxy as a launch flag and Puppeteer supplies the credentials per page. One browser is one exit; sticky sessions make that exit last.


## Launch with a proxy and authenticate

```javascript
import puppeteer from "puppeteer";

const browser = await puppeteer.launch({
  headless: true,
  args: ["--proxy-server=http://res.proxshift.com:9000", "--no-first-run"],
});
const page = await browser.newPage();
await page.authenticate({ username: "USER-cc-us-sid-run1-ttl-30m", password: "PASS" });

await page.goto("https://api.ipify.org", { waitUntil: "domcontentloaded", timeout: 45000 });
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();
```

Call `page.authenticate` before the first navigation on every page you open; Chrome asks for proxy credentials per page. The username carries the country and the session id, so the whole browser stays on one household for the lifetime you set.


## One proxy per browser

Chrome applies `--proxy-server` to the whole browser instance. For several countries or sessions run several browsers (cheap in headless mode), or use `puppeteer.launch` in a pool where each worker owns a session id. Libraries that promise per-page proxies insert a local forwarder; simpler to keep one browser per session.


## Block images, fonts and media

```javascript
await page.setRequestInterception(true);
page.on("request", (req) => {
  const t = req.resourceType();
  if (["image", "media", "font", "stylesheet"].includes(t)) return req.abort();
  req.continue();
});
```


## Consistency

- Set `Accept-Language` and the time zone to the exit's country: `page.setExtraHTTPHeaders({\"Accept-Language\": \"de-DE,de;q=0.9\"})` and `page.emulateTimezone(\"Europe/Berlin\")`.
- Disable WebRTC leaks with `--force-webrtc-ip-handling-policy=disable_non_proxied_udp` in the launch args.
- Keep one browser per account; reuse its user data directory if the account should look like a returning device.


## Errors you will meet

| Symptom | Cause | Fix |
| --- | --- | --- |
| net::ERR_TUNNEL_CONNECTION_FAILED | Gateway refused the CONNECT: credentials, parameter or no exit | Reproduce with cURL -v to read the gateway code |
| net::ERR_PROXY_AUTH_UNSUPPORTED / prompts | authenticate() called after navigation | Call page.authenticate before goto |
| Same IP in every browser | Same session id reused | Use a distinct -sid- per browser or omit it |
| Very slow first load | Household exit plus heavy page | Block resources; raise timeout to 45 s |


## Questions

**Can Puppeteer use SOCKS5 with a password?**

Chrome does not support SOCKS5 authentication. Use the HTTP proxy on port 9000 with page.authenticate, or whitelist your server IP and pass --proxy-server=socks5://res.proxshift.com:9001.

Source: https://proxshift.com/guides/puppeteer-proxy
