Basic SOCKS5 setup
Chrome supports SOCKS proxies through the same flag as HTTP proxies:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
args: ['--proxy-server=socks5://203.0.113.10:1080'],
});
const page = await browser.newPage();
await page.goto('https://httpbin.org/ip');
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();For an overview of the protocol, see SOCKS5 proxies. For Puppeteer proxies in general, see the Puppeteer proxies pillar.
The authentication problem
Chrome doesn't support username/password authentication for SOCKS5 proxies. page.authenticate() only answers HTTP proxy challenges. If your SOCKS5 proxy requires credentials, connections will fail.
You have two good workarounds.
Workaround 1: IP whitelisting
Add your server's IP to the provider's whitelist, and use the SOCKS5 endpoint without credentials. Simplest and fastest.
Workaround 2: A local forwarder
Run a local proxy without authentication that forwards to the authenticated SOCKS5 upstream. proxy-chain can do this in Node:
import puppeteer from 'puppeteer';
import proxyChain from 'proxy-chain';
const local = await proxyChain.anonymizeProxy('socks5://USER:PASS@socks.example.com:1080');
const browser = await puppeteer.launch({ args: [`--proxy-server=${local}`] });
// ...
await browser.close();
await proxyChain.closeAnonymizedProxy(local, true);Alternatively, standalone tools such as gost can expose a local unauthenticated HTTP or SOCKS listener that forwards to an authenticated upstream:
gost -L http://127.0.0.1:8080 -F socks5://USER:PASS@socks.example.com:1080Then point Puppeteer at http://127.0.0.1:8080.
DNS resolution
When Chrome uses a SOCKS5 proxy, it sends hostnames to the proxy for resolution rather than resolving locally, which helps prevent DNS leaks. You can additionally pass a host resolver rule to make sure nothing resolves locally:
args: [
'--proxy-server=socks5://203.0.113.10:1080',
'--host-resolver-rules=MAP * ~NOTFOUND , EXCLUDE 203.0.113.10',
]The EXCLUDE entry ensures the proxy's own address can still be resolved.
Per-context SOCKS5
With recent Puppeteer versions you can set SOCKS5 per browser context:
const ctx = await browser.createBrowserContext({ proxyServer: 'socks5://203.0.113.10:1080' });The same authentication limitation applies. See Puppeteer proxy per page.
SOCKS5 or HTTP for Puppeteer?
For browser automation, HTTP(S) proxies are usually more convenient because page.authenticate() works. Choose SOCKS5 when your provider only offers SOCKS5 for the product you need, or when you want proxy-side DNS without extra configuration.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
ERR_SOCKS_CONNECTION_FAILED | Wrong host/port, credentials required, proxy down | Check endpoint; whitelist IP or use forwarder |
ERR_PROXY_CONNECTION_FAILED | HTTP scheme used for a SOCKS port, or vice versa | Use the right scheme and port |
| Timeouts | Slow proxy | Increase timeout; test speed |
See common proxy errors.
Proxy tip: If you need a pool to run this against, Geonode works with every tool in this guide: rotate per request for stateless pages, or hold a sticky session for logins and pagination. See using Geonode with Puppeteer for working code.
When you might prefer SOCKS5 in Puppeteer
- Your provider only offers a product over SOCKS5, such as some mobile proxy ports.
- You want proxy-side DNS without extra configuration.
- You're routing through an SSH tunnel (
ssh -D 1080 user@servercreates a local SOCKS5 proxy).
Using an SSH tunnel as a SOCKS5 proxy
ssh -N -D 1080 user@your-server.example.comconst browser = await puppeteer.launch({ args: ['--proxy-server=socks5://127.0.0.1:1080'] });All browser traffic exits from your server's IP, with no proxy credentials needed because the tunnel is local. This is a handy way to give Puppeteer a stable datacenter IP you control.
Verifying DNS goes through the proxy
- Launch with the SOCKS5 proxy and the host resolver rule.
- Visit a DNS leak test page.
- Confirm the resolvers shown are near the proxy, not your local network.
Mixing SOCKS5 and HTTP proxies
With per-context proxies, one context can use a SOCKS5 proxy and another an HTTP proxy in the same browser. This is useful when different providers or products use different protocols. See Puppeteer proxy per page.
Performance notes
SOCKS5 and HTTP CONNECT tunnels perform similarly for browser traffic. If SOCKS5 feels slower, the cause is usually the proxy's location or exit quality, not the protocol. See proxy speed test.
For the full Puppeteer picture, see our Puppeteer proxies pillar guide.
SOCKS5 quick reference for Puppeteer
| Need | Solution |
|---|---|
| Unauthenticated SOCKS5 | --proxy-server=socks5://host:port |
| Authenticated SOCKS5 | IP whitelisting, or proxy-chain/gost local forwarder |
| Per-context SOCKS5 | createBrowserContext({ proxyServer: 'socks5://...' }) |
| No local DNS | --host-resolver-rules with an EXCLUDE for the proxy host |
| SSH tunnel | ssh -N -D 1080 user@server then socks5://127.0.0.1:1080 |
| Verify exit | Navigate to an IP echo page |
See SOCKS4 vs SOCKS5 and best SOCKS5 proxies.
A gost forwarder as an alternative to proxy-chain
If you'd rather not add a Node dependency, or you want the same forwarder for several tools, gost does the job as a single binary. It listens locally without authentication and forwards to your authenticated SOCKS5 upstream:
gost -L http://127.0.0.1:8080 -F socks5://USER:PASS@socks.example.com:1080Then point Puppeteer at the local listener:
const browser = await puppeteer.launch({
args: ['--proxy-server=http://127.0.0.1:8080'],
});Chrome talks plain HTTP proxy to gost on your machine, and gost handles the SOCKS5 handshake and credentials. You can also listen as SOCKS5 locally (-L socks5://127.0.0.1:1080) if you want Chrome to keep using SOCKS.
A few precautions:
- Bind to 127.0.0.1, never
0.0.0.0, or anyone who can reach your server can use your proxy without a password. - Run one listener per upstream identity if different pages need different exits, each on its own port.
- Check DNS goes through the proxy. Test with a DNS leak page as described above.
The same pattern works for Selenium, Playwright and command-line tools. For more forwarding patterns, see proxy chains; for the protocol background, SOCKS5 proxies.
Key takeaways
- Puppeteer uses SOCKS5 via
--proxy-server=socks5://host:port, per browser or per context. - Chrome doesn't support SOCKS5 username/password, so use IP whitelisting or a local forwarder (proxy-chain, gost).
- Chrome resolves DNS through SOCKS5 by default; host resolver rules add extra protection against leaks.
- An SSH dynamic tunnel is a quick way to give Puppeteer a SOCKS5 exit through your own server.
- HTTP proxies are usually more convenient for Puppeteer because
page.authenticate()works. See puppeteer proxy authentication.
FAQ
Does Puppeteer support SOCKS5 authentication?
Not natively, because Chrome doesn't. Use IP whitelisting or a local forwarder.
Does SOCKS4 work in Puppeteer?
Yes, with socks4://, but SOCKS5 is preferred. See SOCKS4 vs SOCKS5.
Can Puppeteer send UDP through SOCKS5?
Chrome's SOCKS support is for TCP connections; don't rely on UDP relay.
Editorial note: Proxy providers change their pools, features and prices often, so treat any figures here as typical ranges at the time of writing and confirm current terms with the provider before you buy.