Browser AutomationJavaScript

How to Use Proxies with Puppeteer

Puppeteer is a powerful Node.js library that provides a high-level API for controlling headless Chrome or Chromium. When it comes to proxying, Puppeteer handles settings at the browser launch level through command-line arguments, but it requires an explicit 'page.authenticate()' call to handle credentials. This makes it a robust choice for scraping complex single-page applications (SPAs) that rely heavily on JavaScript rendering and XHR/Fetch requests. By using the ProxyLabs gateway, you can route all browser traffic through a high-quality residential IP, effectively masking your automated nature while maintaining the ability to interact with the page just like a real user. Puppeteer's deep integration with the Chrome DevTools Protocol (CDP) also allows for sophisticated network monitoring and request interception, which can be leveraged to optimize bandwidth usage and improve scraping efficiency on metered residential proxy plans.

Focus: working config first, then the mistakes that usually cause traffic to bypass the proxy or break under concurrency.

Using Proxies with Puppeteer: What to Know

Puppeteer's proxy integration is built directly into the Chromium launch process. When you provide the '--proxy-server' argument, the browser engine is instructed to route all outbound TCP connections through the ProxyLabs gateway. For HTTPS requests, Chromium initiates an HTTP CONNECT handshake. This creates a transparent tunnel where the gateway simply forwards the encrypted bytes, ensuring that your sensitive data and SSL certificates are never exposed to the proxy server itself.

A common architectural challenge with Puppeteer is its global proxy configuration. Because the proxy server is defined at launch, all pages and tabs within that browser instance share the same network identity. For many scraping tasks, this is acceptable, but if you need to simulate multiple users from different countries simultaneously, you will need to manage a pool of browser instances. While this increases memory consumption, it provides the highest level of isolation for your cookies, storage, and fingerprint.

The 'page.authenticate()' method is unique to Puppeteer and its derivatives. It hooks into the browser's credential manager to handle HTTP 407 Proxy Authentication Required challenges automatically. This is a critical feature for residential proxy users, as it allows you to use authenticated gateways without triggering the native auth dialogs that break automation. It's important to note that this authentication persists for the lifetime of the page, making it ideal for multi-step navigation within a single session.

Bandwidth optimization is particularly important in Puppeteer because a real browser engine downloads many more assets than a simple HTTP client. By leveraging Puppeteer's request interception API, you can granularly control which resources are fetched. Blocking requests to known advertising domains, analytics providers, and heavy multimedia files not only saves money on residential data but also speeds up page rendering, making your scrapers significantly more performant.

Stealth is a multifaceted problem in browser automation. Even with a high-quality residential proxy, your browser's fingerprint can give you away. Puppeteer's default configuration exposes several markers, such as the 'navigator.webdriver' flag and specific WebGL vendor strings, that are easily detected by anti-bot services. We strongly recommend using the 'puppeteer-extra-plugin-stealth' to normalize these markers and ensure that your automated sessions are indistinguishable from real human browsing.

When debugging proxy issues, Puppeteer's ability to run in 'headed' mode is invaluable. Seeing the browser interact with the page in real-time allows you to identify if a block is occurring due to an IP ban, a CAPTCHA challenge, or a rendering error. You can also use the Chrome DevTools within the headed instance to inspect the network tab and verify that the 'Proxy-Authorization' headers are being sent correctly and that the responses are coming from the expected geographic region.

Finally, memory management is a key concern for any long-running Puppeteer script. Each browser instance can consume hundreds of megabytes of RAM, and failing to properly close browsers or pages will quickly exhaust your server's resources. Always use 'try...finally' blocks to ensure that 'browser.close()' is called, and consider using a process manager like PM2 to monitor and restart your scraping scripts if they exceed a certain memory threshold.

Installation

npm install puppeteercopy to clipboard

Working Examples

Rotating Proxyjavascript
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: ['--proxy-server=http://gate.proxylabs.app:8080'],
  });

  const page = await browser.newPage();
  await page.authenticate({
    username: 'your-username',
    password: 'your-password',
  });

  try {
    await page.goto('https://httpbin.org/ip', { waitUntil: 'networkidle0' });
    const content = await page.evaluate(() => document.body.innerText);
    console.log(content);
  } catch (error) {
    console.error('Navigation failed:', error.message);
  } finally {
    await browser.close();
  }
})();
Sticky Sessionjavascript
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: ['--proxy-server=http://gate.proxylabs.app:8080'],
  });

  const page = await browser.newPage();
  await page.authenticate({
    username: 'your-username-session-abc123',
    password: 'your-password',
  });

  // All navigations use the same IP
  const urls = [
    'https://example.com/login',
    'https://example.com/dashboard',
    'https://example.com/settings',
  ];

  for (const url of urls) {
    try {
      await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
      console.log(`Loaded: ${url} — ${page.url()}`);
    } catch (error) {
      console.error(`Failed: ${url} — ${error.message}`);
    }
  }

  await browser.close();
})();
Geo-Targeted Browsingjavascript
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: ['--proxy-server=http://gate.proxylabs.app:8080'],
    headless: 'new',
  });

  const page = await browser.newPage();
  await page.authenticate({
    username: 'your-username-country-US-city-NewYork',
    password: 'your-password',
  });

  await page.goto('https://httpbin.org/ip', { waitUntil: 'networkidle0' });
  const ip = await page.evaluate(() => document.body.innerText);
  console.log('NYC IP:', ip);

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

What matters in practice

  • Headless Chrome execution that enables realistic browser fingerprinting and bypasses simple bot detection systems.
  • Support for per-page authentication to the proxy gateway, allowing for granular control over network identity within a single script.
  • Powerful network request interception capabilities to block heavy assets like images and CSS, significantly reducing residential proxy data consumption.
  • Full access to the Chrome DevTools Protocol (CDP) for monitoring network performance and debugging proxy-related connection issues.
  • Native support for high-quality screenshot and PDF generation, allowing you to capture the rendered state of any page through a residential IP.
  • Sophisticated event handling for navigation and network states, ensuring that you only interact with pages after they are fully loaded and stabilized.

Operational Notes

01

Always call 'page.authenticate()' before initiating your first 'page.goto()' call. If the browser attempts to load a URL before authentication is correctly configured, the proxy gateway will return an HTTP 407 error and immediately terminate the navigation.

02

Enable request interception with 'page.setRequestInterception(true)' to block media-heavy assets like images and videos. Since residential proxy data is often metered, this simple optimization can reduce your bandwidth costs by over 50% on many websites.

03

When running Puppeteer in a Dockerized environment, ensure you launch with the '--disable-setuid-sandbox' and '--no-sandbox' flags. These are often required for the browser binary to execute correctly within restricted container environments.

04

If you need to rotate proxies per page, you must launch separate browser instances or use a tool like Playwright. Puppeteer's proxy settings are global to the browser process and cannot be changed dynamically once the browser has started.

05

Set a generous 'timeout' in your 'page.goto()' options. Residential proxies can occasionally experience higher latency than datacenter IPs during the initial TLS handshake, and a 30-second limit is a safe baseline for most scraping tasks.

06

Use the 'puppeteer-extra-plugin-stealth' package to patch common automation markers like navigator.webdriver. This is essential for preventing detection by high-security anti-bot systems when using proxies to scrape protected pages.

Frequently Asked Questions

Why does my Puppeteer browser show a native login popup?

The native login popup appears when the proxy gateway requires authentication and the 'page.authenticate()' method either hasn't been called or was called too late. Puppeteer must proactively send the credentials to the proxy to avoid this browser-level dialog, which cannot be automated. To fix this, ensure that 'page.authenticate()' is the very first action you perform on a new page, even before setting any headers or navigating to a test URL.

How do I handle connection timeouts when using residential proxies in Puppeteer?

To handle proxy-related timeouts, you should increase the default navigation timeout in 'page.goto()' and wrap your navigation logic in a retry loop. Residential proxies are more prone to intermittent connectivity issues than fixed datacenter IPs. Implementing a exponential backoff strategy for retries will help your script recover from temporary gateway dropouts. Additionally, monitoring the 'requestfailed' event on the page object can provide valuable diagnostic information about why a specific proxy connection failed.

Does Puppeteer support WebRTC over residential proxies?

By default, WebRTC may attempt to establish direct peer-to-peer connections that could leak your real IP address, bypassing the proxy. To prevent this, you should launch Puppeteer with the '--disable-features=WebRtcHideLocalIpsWithMdns' flag or use a plugin to disable WebRTC entirely. This ensures that all network traffic, including media streams and signaling data, is strictly routed through the ProxyLabs residential tunnel, maintaining your anonymity throughout the session.

Nearby Guides

Need residential IPs for Puppeteer?

Get access to 30M+ residential IPs in 195+ countries. Pay-as-you-go from £2.50/GB. No subscriptions, no commitments.

GET STARTED

Related guides