Geonode logo
Carl Gamutan

Carl Gamutan

Updated: October 2, 2026

Published: April 8, 2022

How To Use Proxies With Puppeteer

Puppeteer is a node library that gives its users a high-level headless Chrome API. Here's how to create a proxy server for it!

Why Puppeteer needs a proxy

Proxies for Puppeteer let the tool connect through a different IP address instead of always using the IP of the machine running it. This is useful for location-based tasks, testing, monitoring, and other jobs where the connection source matters.

Puppeteer still handles the main task. The proxy handles where the connection comes from.

What happens without one: IP bans, rate limits, geo walls

Without a proxy, websites keep seeing the same IP. As activity increases, that IP may hit a rate limit or get blocked.

Location can matter too. A page opened from Germany may not return the same content as one opened from the US.

A proxy for Puppeteer makes it possible to connect from different IPs and locations when needed.

Which proxy type to use with Puppeteer

The right proxy type depends on the job.

Proxy typeScrapingAccount managementTestingMonitoring
ResidentialGood when location and IP source matterUseful when accounts need residential IPsGood for location-based testingUseful for checking content from different locations
ISPGood when a stable IP is neededUseful for longer sessions on one IPGood for testing with a consistent IPUseful for ongoing checks from the same IP
DatacenterGood for speed and larger request volumesBetter when residential IPs are not requiredGood for general testingGood for frequent automated checks

Residential proxies are useful when the IP source and location matter. ISP proxies work well when the same IP needs to stay active for longer. Datacenter proxies make sense when the main focus is speed and scale.

The best option also depends on whether the task needs geo-targeting, a stable connection, or access to a larger pool of IPs.

How to connect a proxy in Puppeteer

The Puppeteer proxy setup needs the Geonode host, port, username, and password. Keep the credentials in environment variables, then load them when setting up the proxy in code.

Using Geonode? Get the username and password from Access Credentials and the host, port, and protocol from Proxy Server Information.

Settings path or code

For Puppeteer, pass the proxy host and port through --proxy-server when launching the browser:

import puppeteer from "puppeteer";
import "dotenv/config";

const browser = await puppeteer.launch({
  headless: true,
  args: [
    `--proxy-server=http://${process.env.GEONODE_PROXY_HOST}:${process.env.GEONODE_PROXY_PORT}`,
  ],
});

Then create the page and provide the proxy credentials:

const page = await browser.newPage();

await page.authenticate({
  username: process.env.GEONODE_PROXY_USER,
  password: process.env.GEONODE_PROXY_PASS,
});

Keep the actual username and password in environment variables instead of putting them directly in the source file. This setup successfully returned HTTP 200 through the proxy in our test.

Authentication format host:port:user:pass

Geonode gives you four values:

proxy.geonode.io:PORT:USERNAME:PASSWORD

For Puppeteer, keep the values separate. Store them in environment variables:

GEONODE_PROXY_HOST=proxy.geonode.io
GEONODE_PROXY_PORT=9000
GEONODE_PROXY_USER=USERNAME
GEONODE_PROXY_PASS=PASSWORD

Load the host and port through --proxy-server, then authenticate the page:

const browser = await puppeteer.launch({
  headless: true,
  args: [
    `--proxy-server=http://${process.env.GEONODE_PROXY_HOST}:${process.env.GEONODE_PROXY_PORT}`,
  ],
});

const page = await browser.newPage();

await page.authenticate({
  username: process.env.GEONODE_PROXY_USER,
  password: process.env.GEONODE_PROXY_PASS,
});

We tested this with valid credentials and received HTTP 200. With an incorrect password, the proxy returned HTTP 407 and:

Authentication error. Please check your authentication settings.

Rotation vs sticky session in Puppeteer

If the requests do not need to keep the same IP, use rotation.

For our test, we launched Puppeteer with the HTTP rotating port:

const browser = await puppeteer.launch({
  headless: true,
  args: ["--proxy-server=http://proxy.geonode.io:9000"],
});

const page = await browser.newPage();

await page.authenticate({
  username: process.env.GEONODE_PROXY_USER,
  password: process.env.GEONODE_PROXY_PASS,
});

We made five requests using fresh browser sessions:

Request 1: 108.31.182.167
Request 2: 45.186.93.125
Request 3: 109.254.131.42
Request 4: 109.153.11.141
Request 5: 37.113.173.139

Unique IPs: 5

Rotation: Yes

All five requests returned different IPs in this test. That confirms rotation worked during the run, but it does not guarantee a new IP for every future request.

If related requests need to stay on the same IP, use a sticky session instead. Use the sticky port and add the session details to the username:

const browser = await puppeteer.launch({
  headless: true,
  args: ["--proxy-server=http://proxy.geonode.io:10000"],
});

const page = await browser.newPage();

await page.authenticate({
  username:
    `${process.env.GEONODE_PROXY_USER}-session-blogpuppeteer01-lifetime-10`,
  password: process.env.GEONODE_PROXY_PASS,
});

We made three requests using the same session:

Request 1: 178.64.64.40
Request 2: 178.64.64.40
Request 3: 178.64.64.40

Same IP: Yes

All three requests used the same IP.

See the Geonode guides for rotating proxies and sticky sessions for the available settings.

Common proxy errors in Puppeteer and how to fix them

If the proxy is not working, start with the connection details. Check the username and password, then the host, port, and protocol. The error returned by Puppeteer can usually help narrow down the problem.

407 Proxy Authentication Required

A 407 usually points to an authentication problem.

When we tested Puppeteer with an incorrect password, the proxy returned:

HTTP status: 407
Authentication error. Please check your authentication settings.

Check the username and password first. If they are correct, make sure page.authenticate() is called after creating the page.

ERR_TUNNEL_CONNECTION_FAILED / connection refused

A connection error usually means Puppeteer could not reach the proxy.

Check the host and port first. Then make sure the protocol matches the proxy server being used.

In our failed connection test, Puppeteer did not return ERR_TUNNEL_CONNECTION_FAILED. Using an unreachable proxy port returned:

net::ERR_CONNECTION_RESET at http://ip-api.com/json

The exact Chromium error can therefore differ depending on how the connection fails.

Timeouts and empty responses

A timeout means the page did not receive a response within the configured time.

First, check whether the target URL works and whether the proxy can connect. If both are working, check the timeout passed to page.goto().

For our test, we used a non-routable proxy with a five-second timeout:

await page.goto(url, {
  timeout: 5000,
});

Puppeteer returned:

TimeoutError: Navigation timeout of 5000 ms exceeded

Setting an explicit timeout can help a script fail quickly when the proxy connection hangs.

ERR_NO_SUPPORTED_PROXIES

One Puppeteer-specific problem we found was putting the username and password directly inside --proxy-server.

This configuration failed:

--proxy-server=http://USERNAME:PASSWORD@proxy.geonode.io:9000

Puppeteer returned:

net::ERR_NO_SUPPORTED_PROXIES

The fix is to pass only the proxy server through the launch argument:

args: ["--proxy-server=http://proxy.geonode.io:9000"]

Then authenticate separately:

await page.authenticate({
  username: process.env.GEONODE_PROXY_USER,
  password: process.env.GEONODE_PROXY_PASS,
});

After changing the setup, the request succeeded with HTTP 200.

Puppeteer + Geonode: what you get

Puppeteer handles the requests or connections in the application. Geonode handles the proxy connection.

You can choose residential, ISP, or datacenter proxies based on the job, then use rotation, sticky sessions, and geo-targeting where needed. This keeps the proxy setup separate from the rest of the application code.

Plans vary by proxy type, with some options priced per GB.

FAQ

Does Puppeteer support SOCKS5 proxies?

Authenticated SOCKS5 did not work with the Puppeteer setup we tested.

We tried Geonode's SOCKS5 rotating port with page.authenticate(), but Puppeteer returned:

net::ERR_SOCKS_CONNECTION_FAILED

We also tried embedding the credentials in --proxy-server, which returned:

net::ERR_NO_SUPPORTED_PROXIES

Because none of the tested authenticated SOCKS5 configurations worked, the verified HTTP setup with --proxy-server and page.authenticate() is the safer option for this configuration.

Can I rotate IPs per request in Puppeteer?

Yes, Puppeteer can use a rotating proxy when the browser is launched through the rotating proxy configuration.

In our test, five fresh browser sessions returned five different IPs. That confirms rotation occurred during the test, but a different IP is not guaranteed for every request or browser session.

Is there a free trial?

Yes. Geonode offers a free trial, so the proxy can be tested with Puppeteer before moving to a paid plan. Check the current free trial and plans.

Where should I configure the proxy in Puppeteer?

Set the proxy host and port in puppeteer.launch() using --proxy-server.

Then call page.authenticate() after creating each page to provide the username and password:

const browser = await puppeteer.launch({
  args: ["--proxy-server=http://proxy.geonode.io:9000"],
});

const page = await browser.newPage();

await page.authenticate({
  username: process.env.GEONODE_PROXY_USER,
  password: process.env.GEONODE_PROXY_PASS,
});

This was the configuration that worked in our tests.

Should I put the proxy username and password in --proxy-server?

No. Keep the credentials separate when using this Puppeteer setup.

Embedding USERNAME:PASSWORD@ directly in --proxy-server returned ERR_NO_SUPPORTED_PROXIES in our test. Passing only the host and port there, then using page.authenticate() for the credentials, worked successfully.