Node.js · setup guide

Puppeteer proxy setup

Puppeteer splits the proxy in two. Chrome gets the host and port as a launch flag, and each page answers the auth challenge with page.authenticate. Forget the second half on any page and that page gets a 407.
You will need

Residentialresi.proxymonkey.io:8000

ISP or datacenterIP:PORT

CredentialsUSER:PASS

Copy your own from the dashboard, which also lists the host and port for every order. Where it differs from this page, the dashboard is right.

Install

Node.js 18 or newer. The package downloads a matching browser on install.

terminal
npm i puppeteer

Rotating residential

--proxy-server takes a host and port only; credentials in it are ignored. Call authenticate before the first navigation.

rotate.mjs
import puppeteer from "puppeteer";

const browser = await puppeteer.launch({
  args: ["--proxy-server=http://resi.proxymonkey.io:8000"],
});
const page = await browser.newPage();
await page.authenticate({ username: "USER", password: "PASS" });

await page.goto("https://httpbin.org/ip");
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();

A static datacenter or ISP IP

To run several IPs from one browser, give each browser context its own proxyServer. Older Puppeteer versions call this createIncognitoBrowserContext. For an ISP order, use the host and port from your dashboard.

static.mjs
import puppeteer from "puppeteer";

const browser = await puppeteer.launch();
const context = await browser.createBrowserContext({
  proxyServer: "http://IP:PORT",
});
const page = await context.newPage();
await page.authenticate({ username: "USER", password: "PASS" });

await page.goto("https://httpbin.org/ip");
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();

Keeping one identity

A browser context keeps its own cookies and storage, so one context per static IP gives you separate identities that stay separate. On the rotating gateway, the requests behind a single page load can leave from different addresses; for logins and checkouts use a static IP or a residential sticky session, whose setting for your account is in the dashboard.

Specific to Puppeteer

Things worth knowing

Popups and new tabs need credentials too

authenticate is per page. A link that opens a new tab, or a window.open popup, starts without it and hits a 407. Listen for new targets and authenticate them as they appear.

popups.mjs
browser.on("targetcreated", async (target) => {
  const page = await target.page();
  if (page) await page.authenticate({ username: "USER", password: "PASS" });
});

Skip images with request interception

Every image, font and video is metered, request bytes plus response bytes. Abort the resource types you do not need.

block.mjs
await page.setRequestInterception(true);
page.on("request", (req) => {
  if (["image", "media", "font"].includes(req.resourceType())) req.abort();
  else req.continue();
});

Screenshots are free, page loads are not

Taking a screenshot of a page you already loaded moves no traffic. Grab everything you need from one load instead of navigating twice.

When it breaks

Common errors and fixes

  • The page shows a 407, or page.goto rejects on its first call

    Why
    authenticate was not called on this page, or was called after goto.
    Fix
    Authenticate right after newPage(), and cover new tabs with the targetcreated listener above.
  • net::ERR_TUNNEL_CONNECTION_FAILED

    Why
    The gateway refused the CONNECT, most often because the credentials were rejected.
    Fix
    Check username and password against the dashboard, then test the same pair with curl.
  • TimeoutError: Navigation timeout of 30000 ms exceeded

    Why
    Waiting for the full load event on a heavy page through a slow exit.
    Fix
    Pass waitUntil: "domcontentloaded", block heavy resources, and set page.setDefaultNavigationTimeout if you need longer.
  • net::ERR_CERT_AUTHORITY_INVALID or another net::ERR_CERT_ error

    Why
    The target's certificate. The proxy passes TLS through untouched.
    Fix
    The launch option to accept insecure certificates exists for testing. Do not ship it.

A failed connection that moved no data is not billed. Retries you send are billed like any other request, and each shows as its own line in your usage log.

The community layer

Puppeteer still misbehaving?

Paste the error and the few lines that set up the proxy into Discord, with the password taken out. Someone there has seen it before.

Join the Discord

4,200+monkeys in the Discord

  • Help from humans

    Post your error, get an answer. Usually in minutes, usually from someone who has hit the same wall.

  • A status bot that tells on us

    Pool health, incidents and maintenance posted automatically. Including the bad days.

  • Deals and free traffic

    Bonus GB drops, early access to new pools, and the occasional giveaway for a good bug report.

Join the Discord4,200+ monkeys, free to lurk