Tutorials12 min read

Puppeteer Proxy Setup — Step-by-Step Guide with Code Examples

ResProxy Team
Puppeteer Proxy Setup — Step-by-Step Guide with Code Examples

Puppeteer is Google's official Node.js library for controlling headless Chrome. It is faster and more resource-efficient than Selenium for JavaScript-heavy scraping, and it pairs exceptionally well with rotating proxies for large-scale data collection.

In this guide, you will learn how to configure proxies at the browser level and the page level, handle proxy authentication, rotate IPs automatically, and apply stealth techniques to avoid detection. Every example is a complete, runnable script.

Puppeteer proxy setup guide
Puppeteer proxy setup guide

Why Puppeteer Needs Proxies

Puppeteer launches a real Chromium instance, which means target websites see a genuine browser fingerprint. This is an advantage over raw HTTP requests, but it does not protect you from IP-based blocking. When you send hundreds or thousands of requests from the same IP, even the most realistic browser fingerprint will not save you.

Rotating residential proxies solve this by assigning a new residential IP for each connection. Combined with Puppeteer's stealth capabilities, this creates a scraping setup that is extremely difficult for anti-bot systems to detect.

Prerequisites

You need Node.js 18 or later. Install Puppeteer:

`bash npm install puppeteer `

Puppeteer automatically downloads a compatible Chromium binary. If you want to use your system Chrome instead, install puppeteer-core and specify the executable path.

Basic Proxy Configuration

The simplest way to proxy all Puppeteer traffic is with the --proxy-server launch argument:

`javascript const puppeteer = require("puppeteer");

const PROXY = "http://gate.resproxy.io:7777";

(async () => { const browser = await puppeteer.launch({ headless: "new", args: [ --proxy-server=${PROXY}, "--no-sandbox", "--disable-setuid-sandbox", ], });

const page = await browser.newPage(); await page.goto("https://httpbin.org/ip", { waitUntil: "domcontentloaded" });

const content = await page.evaluate(() => document.body.innerText); console.log("Proxy IP:", content);

await browser.close(); })(); `

This routes all traffic from every page and tab through the specified proxy. The proxy applies at the browser level, so every page.goto() call uses it automatically.

Puppeteer proxy authentication
Puppeteer proxy authentication

Authenticated Proxy Setup

Most proxy services require username and password authentication. Puppeteer provides the page.authenticate() method for this:

`javascript const puppeteer = require("puppeteer");

const PROXY_HOST = "gate.resproxy.io"; const PROXY_PORT = 7777; const PROXY_USER = "your_username"; const PROXY_PASS = "your_password";

(async () => { const browser = await puppeteer.launch({ headless: "new", args: [ --proxy-server=http://${PROXY_HOST}:${PROXY_PORT}, "--no-sandbox", ], });

const page = await browser.newPage();

// Authenticate with the proxy await page.authenticate({ username: PROXY_USER, password: PROXY_PASS, });

await page.goto("https://httpbin.org/ip", { waitUntil: "networkidle2" }); const body = await page.evaluate(() => document.body.innerText); console.log("Response:", body);

await browser.close(); })(); `

The page.authenticate() call must happen before any navigation. It sets up a handler that automatically responds to 407 Proxy Authentication Required challenges for all subsequent requests on that page.

Page-Level Proxy Routing

Sometimes you need different proxies for different pages within the same browser instance. You can achieve this by intercepting requests:

`javascript const puppeteer = require("puppeteer");

(async () => { const browser = await puppeteer.launch({ headless: "new", args: ["--proxy-server=http://gate.resproxy.io:7777", "--no-sandbox"], });

// Page 1 — uses proxy with authentication set A const page1 = await browser.newPage(); await page1.authenticate({ username: "user_us", password: "pass123" }); await page1.goto("https://example.com/us-page"); console.log("US page title:", await page1.title());

// Page 2 — uses proxy with authentication set B (different geo) const page2 = await browser.newPage(); await page2.authenticate({ username: "user_uk", password: "pass456" }); await page2.goto("https://example.com/uk-page"); console.log("UK page title:", await page2.title());

await browser.close(); })(); `

By using different credentials per page, you can route each tab through a different geographic endpoint, which is useful for comparing localized content or prices across regions.

Rotating Proxies Automatically

For scraping multiple pages, you want a fresh IP for each request. With ResProxy's rotating endpoint, each new connection gets a different IP. Here is a production-ready scraping loop:

`javascript const puppeteer = require("puppeteer");

const PROXY = "http://gate.resproxy.io:7777"; const PROXY_USER = "your_username"; const PROXY_PASS = "your_password";

const URLS = [ "https://example.com/product/1", "https://example.com/product/2", "https://example.com/product/3", "https://example.com/product/4", "https://example.com/product/5", ];

async function scrapePage(url) { const browser = await puppeteer.launch({ headless: "new", args: [--proxy-server=${PROXY}, "--no-sandbox"], });

try { const page = await browser.newPage(); await page.authenticate({ username: PROXY_USER, password: PROXY_PASS });

await page.setViewport({ width: 1920, height: 1080 }); await page.setUserAgent( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " + "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" );

await page.goto(url, { waitUntil: "networkidle2", timeout: 30000 });

const data = await page.evaluate(() => ({ title: document.title, text: document.body.innerText.substring(0, 200), }));

return { url, ...data, success: true }; } catch (err) { return { url, error: err.message, success: false }; } finally { await browser.close(); } }

(async () => { for (const url of URLS) { const result = await scrapePage(url); console.log(result); // Random delay between 1-3 seconds await new Promise((r) => setTimeout(r, 1000 + Math.random() * 2000)); } })(); `

Each call to scrapePage launches a new browser, which creates a new proxy connection and receives a new IP. The random delay between requests mimics human browsing patterns.

Puppeteer stealth techniques
Puppeteer stealth techniques

Stealth Techniques

Anti-bot systems detect Puppeteer through several signals. The puppeteer-extra package with the stealth plugin patches most of these:

`bash npm install puppeteer-extra puppeteer-extra-plugin-stealth `

`javascript const puppeteer = require("puppeteer-extra"); const StealthPlugin = require("puppeteer-extra-plugin-stealth");

puppeteer.use(StealthPlugin());

const PROXY = "http://gate.resproxy.io:7777";

(async () => { const browser = await puppeteer.launch({ headless: "new", args: [--proxy-server=${PROXY}, "--no-sandbox"], });

const page = await browser.newPage(); await page.authenticate({ username: "your_user", password: "your_pass" });

// Stealth plugin automatically patches: // - navigator.webdriver // - chrome.runtime // - WebGL vendor/renderer // - Language and plugin arrays // - Permission queries

await page.goto("https://bot.sannysoft.com/", { waitUntil: "networkidle2" }); await page.screenshot({ path: "stealth-test.png", fullPage: true });

await browser.close(); })(); `

The stealth plugin modifies dozens of browser properties to make Puppeteer indistinguishable from a regular Chrome session. Combined with residential proxies, this defeats the vast majority of bot detection systems.

Handling Timeouts and Errors

Proxy connections can occasionally timeout or fail. Here is a robust wrapper with retry logic:

`javascript async function scrapeWithRetry(url, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const browser = await puppeteer.launch({ headless: "new", args: ["--proxy-server=http://gate.resproxy.io:7777", "--no-sandbox"], });

const page = await browser.newPage(); await page.authenticate({ username: "user", password: "pass" }); page.setDefaultNavigationTimeout(30000);

await page.goto(url, { waitUntil: "domcontentloaded" }); const html = await page.content(); await browser.close(); return html; } catch (err) { console.error(Attempt ${attempt} failed: ${err.message}); if (attempt === maxRetries) throw err; await new Promise((r) => setTimeout(r, 2000 * attempt)); } } } `

Performance Optimization

When scraping at scale, every millisecond counts. These optimizations reduce resource usage and increase throughput:

`javascript const page = await browser.newPage();

// Block images, fonts, and stylesheets to speed up loading await page.setRequestInterception(true); page.on("request", (req) => { const type = req.resourceType(); if (["image", "font", "stylesheet", "media"].includes(type)) { req.abort(); } else { req.continue(); } });

// Use domcontentloaded instead of networkidle2 when you only need HTML await page.goto("https://example.com", { waitUntil: "domcontentloaded" }); `

Blocking unnecessary resources can reduce page load times by 50-80 percent and significantly lower bandwidth consumption through your proxy.

Best Practices

  1. Launch a new browser per task for maximum IP diversity with rotating proxies
  2. Always call page.authenticate() before the first page.goto()
  3. Use the stealth plugin to avoid detection on protected sites
  4. Block unnecessary resources to reduce bandwidth and improve speed
  5. Set realistic viewports and user agents to match your proxy's geographic location
  6. Implement retry logic with exponential backoff for production workloads

Next Steps

Set up your proxy credentials through the getting started guide and you can have your first Puppeteer scraper running in under five minutes. For the full Puppeteer API reference, visit pptr.dev.

If you are comparing browser automation tools, you might also be interested in our Selenium proxy setup guide or our overview of rotating residential proxies.

ResProxy Team

Editorial Team

The ResProxy editorial team combines expertise in proxy technology, web scraping, network infrastructure, and online privacy to deliver actionable guides and industry insights.