Web Scraping & Automation

Using SOCKS5 Proxies With Puppeteer

How to use SOCKS5 proxies in Puppeteer: the --proxy-server flag, why SOCKS5 authentication fails in Chrome, IP whitelisting and local forwarder workarounds, and DNS behaviour.

By Team of Monkeys Editorial Updated 4 min read Affiliate disclosure

This guide contains affiliate links to Geonode. If you buy through them we may earn a commission, at no extra cost to you.

Basic SOCKS5 setup

Chrome supports SOCKS proxies through the same flag as HTTP proxies:

javascript
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:

javascript
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:

bash
gost -L http://127.0.0.1:8080 -F socks5://USER:PASS@socks.example.com:1080

Then 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:

javascript
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:

javascript
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

ErrorCauseFix
ERR_SOCKS_CONNECTION_FAILEDWrong host/port, credentials required, proxy downCheck endpoint; whitelist IP or use forwarder
ERR_PROXY_CONNECTION_FAILEDHTTP scheme used for a SOCKS port, or vice versaUse the right scheme and port
TimeoutsSlow proxyIncrease 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@server creates a local SOCKS5 proxy).

Using an SSH tunnel as a SOCKS5 proxy

bash
ssh -N -D 1080 user@your-server.example.com
javascript
const 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

  1. Launch with the SOCKS5 proxy and the host resolver rule.
  2. Visit a DNS leak test page.
  3. Confirm the resolvers shown are near the proxy, not your local network.

See DNS leaks and proxies.

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

NeedSolution
Unauthenticated SOCKS5--proxy-server=socks5://host:port
Authenticated SOCKS5IP whitelisting, or proxy-chain/gost local forwarder
Per-context SOCKS5createBrowserContext({ proxyServer: 'socks5://...' })
No local DNS--host-resolver-rules with an EXCLUDE for the proxy host
SSH tunnelssh -N -D 1080 user@server then socks5://127.0.0.1:1080
Verify exitNavigate 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:

bash
gost -L http://127.0.0.1:8080 -F socks5://USER:PASS@socks.example.com:1080

Then point Puppeteer at the local listener:

javascript
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.

Affiliate disclosure: Team of Monkeys is a Geonode affiliate. Links and banners marked as sponsored, and links to Geonode in the text, use our referral link, and we may earn a commission if you buy through them, at no extra cost to you. Our explanations and comparisons are written to be useful whichever provider you choose.

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.