Playwright vs. Puppeteer: Proxy Architecture Differences

While both tools automate Chromium, Firefox, and WebKit, their proxy support models differ significantly:

  • Playwright: Supports configuring proxies both at the browser level (via chromium.launch({ proxy })) and independently for each BrowserContext (via browser.newContext({ proxy })). Credentials (username, password) are configured directly in the launch config.
  • Puppeteer: Passes the proxy host as a command-line Chromium flag (--proxy-server=http://host:port) and handles authentication via an asynchronous listener on the page: page.authenticate({ username, password }).

1. Playwright Python Integration

In Python, pass your backconnect proxy dictionary to async_playwright().chromium.launch(). The following script connects to a rotating residential gateway, opens an isolated context, and verifies the IP:

import asyncio
from playwright.async_api import async_playwright

async def run_scraper():
    # 2Captcha Residential Proxy endpoint (automatic IP rotation per connection)
    proxy_config = {
        "server": "http://proxy.2captcha.com:8080",
        "username": "customer-user_id-zone-res",
        "password": "your_secure_password"
    }

    async with async_playwright() as p:
        # Launch Chromium with proxy configured at the browser level
        browser = await p.chromium.launch(
            headless=True,
            proxy=proxy_config,
            args=[
                "--disable-blink-features=AutomationControlled",
                "--no-first-run"
            ]
        )

        # Create isolated browser context with matching locale and timezone
        context = await browser.new_context(
            locale="en-US",
            timezone_id="America/New_York",
            viewport={"width": 1920, "height": 1080}
        )

        page = await context.new_page()

        # Verify egress IP address
        await page.goto("https://2-proxy.com/my-ip/")
        print("Connected via Proxy! Page Title:", await page.title())

        await browser.close()

if __name__ == "__main__":
    asyncio.run(run_scraper())

2. Playwright Node.js / TypeScript Integration

In Node.js, Playwright's multi-context architecture allows you to run multiple concurrent scraping threads from a single browser instance, saving memory and CPU:

import { chromium } from 'playwright';

async function scrapeWithProxy() {
  const browser = await chromium.launch({
    proxy: {
      server: 'http://proxy.2captcha.com:8080',
      username: 'customer-user_id-zone-res',
      password: 'your_secure_password'
    }
  });

  // Multiple isolated browser contexts can share the pool or specify individual proxies
  const context = await browser.newContext({
    permissions: ['geolocation'],
    geolocation: { latitude: 40.7128, longitude: -74.0060 }
  });

  const page = await context.newPage();
  await page.goto('https://httpbin.org/ip');
  console.log(await page.textContent('body'));

  await browser.close();
}

scrapeWithProxy();

3. Puppeteer Node.js Integration

In Puppeteer, pass the proxy server through the args array and authenticate before loading the first URL:

const puppeteer = require('puppeteer');

async function scrapeWithPuppeteer() {
  // Launch browser pointing to backconnect proxy server
  const browser = await puppeteer.launch({
    headless: "new",
    args: ['--proxy-server=http://proxy.2captcha.com:8080']
  });

  const page = await browser.newPage();

  // Authenticate proxy on the page instance
  await page.authenticate({
    username: 'customer-user_id-zone-res',
    password: 'your_secure_password'
  });

  await page.goto('https://2-proxy.com/my-ip/');
  console.log('Successfully navigated via proxy');

  await browser.close();
}

scrapeWithPuppeteer();

Preventing WebRTC IP Leaks

Even when routing all HTTP requests through a residential proxy, Chromium's built-in WebRTC (Web Real-Time Communication) feature can expose your real host public and local IP addresses to anti-bot inspection scripts through STUN candidate requests.

To prevent WebRTC leaks in headless Chromium:

--disable-features=WebRtcHideLocalIpsWithMdns
--enforce-webrtc-ip-permission-check

You can test your browser configuration for leaks instantly using our free interactive tool: What Is My IP & WebRTC Leak Detector.

Related Resources