NewUnlimited residential proxies: unmetered traffic on a fixed price. From $33.25/day

JavaScript ยท Integration guide

How to use proxies with Puppeteer

Puppeteer points Chrome at a proxy with a launch flag and answers the gateway login with page.authenticate(). This guide adds sticky sessions, one IP per browser context, location matching and leaner page loads.

  • 6 steps
  • 12 min setup
  • Copy-paste code

Before you start

  • Node.js 22 or newer
  • Puppeteer 22 or newer
  • A Proxonym residential or mobile plan
Get proxy credentials

Already a customer? Your username and password are in the dashboard.

  1. Install Puppeteer

    Installing the package also downloads a matching build of Chrome for Testing. Save the examples as .mjs files to use import and top-level await.

    Shell
    npm install puppeteer
  2. Launch Chrome through the gateway

    Chrome ignores credentials inside --proxy-server, so pass only the host and port there and supply the username and password with page.authenticate() before the first navigation.

    JavaScript
    // launch.mjs
    import puppeteer from 'puppeteer';
    
    const browser = await puppeteer.launch({
      args: ['--proxy-server=http://gw.proxonym.com:8000'],
    });
    const page = await browser.newPage();
    await page.authenticate({ username: 'USERNAME', password: 'PASSWORD' });
    
    await page.goto('https://api.ipify.org');
    console.log('Exit IP:', await page.evaluate(() => document.body.innerText));
    await browser.close();
  3. Keep one IP for the whole session

    A page opens many connections, and with a rotating username each one can exit from a different IP. Add a -session- ID so every connection shares one IP, and set -lifetime- longer than the job, up to 120 minutes.

    JavaScript
    import { randomBytes } from 'node:crypto';
    
    const session = randomBytes(4).toString('hex');
    await page.authenticate({
      username: `USERNAME-country-us-session-${session}-lifetime-30`,
      password: 'PASSWORD',
    });
  4. Run one IP per browser context

    Browser contexts keep separate cookies and connections, and each can use its own proxy. Give every context a different session ID or country to run several identities from one Chrome process.

    JavaScript
    // contexts.mjs
    import { randomBytes } from 'node:crypto';
    import puppeteer from 'puppeteer';
    
    const browser = await puppeteer.launch();
    
    async function openIdentity(country) {
      const context = await browser.createBrowserContext({
        proxyServer: 'http://gw.proxonym.com:8000',
      });
      const page = await context.newPage();
      await page.authenticate({
        username: `USERNAME-country-${country}-session-${randomBytes(4).toString('hex')}-lifetime-30`,
        password: 'PASSWORD',
      });
      return page;
    }
    
    const pages = await Promise.all(['us', 'gb', 'de'].map(openIdentity));
    for (const page of pages) {
      await page.goto('https://api.ipify.org');
      console.log(await page.evaluate(() => document.body.innerText));
    }
    await browser.close();
  5. Match the browser to the location

    Target a country, state or city in the username, then align the timezone and language with it so the browser and the IP tell the same story.

    JavaScript
    await page.authenticate({
      username: 'USERNAME-country-de-city-berlin-session-b3x9-lifetime-30',
      password: 'PASSWORD',
    });
    await page.emulateTimezone('Europe/Berlin');
    await page.setExtraHTTPHeaders({ 'Accept-Language': 'de-DE,de;q=0.9' });
    
    await page.goto('https://ipinfo.io/json');
    console.log(await page.evaluate(() => document.body.innerText));
  6. Save traffic and handle errors

    Residential traffic is metered per GB, so block images, media and fonts you do not need. A refused tunnel makes page.goto() throw net::ERR_TUNNEL_CONNECTION_FAILED, which is worth a retry with a new session ID, while a rejected login comes back as a 407 status.

    JavaScript
    await page.setRequestInterception(true);
    page.on('request', (request) => {
      if (['image', 'media', 'font'].includes(request.resourceType())) request.abort();
      else request.continue();
    });
    
    try {
      const response = await page.goto('https://example.com', {
        waitUntil: 'domcontentloaded',
        timeout: 60_000,
      });
      console.log('Status:', response?.status());
    } catch (err) {
      console.error('Navigation failed:', err.message);
    }

Frequently asked questions

Why does Puppeteer fail with ERR_TUNNEL_CONNECTION_FAILED?

The gateway refused to open a tunnel to the target. A 402 means your balance is empty or the plan has expired, and a 403 means the target is blocked under the acceptable use policy, while 502 and 504 are transient, so retry with a new session ID. Login problems look different: a 407 page status, or ERR_INVALID_AUTH_CREDENTIALS when page.authenticate() was not called.

Can each page or tab use a different IP?

Yes. Create a browser context per identity with its own proxyServer, open pages inside it, and authenticate each page with a username that carries a different session ID or country. Pages in the same context share cookies and connections, so treat one context as one identity and one sticky IP.

Does headless mode change how the proxy works?

No. The proxy flag, the authentication step and the username parameters are identical in headless and headed mode. What differs is the browser fingerprint, so align the timezone, language and viewport with the exit location, and keep request rates realistic for the site you visit.

How can I reduce traffic per page?

Block images, media and fonts with request interception, wait for domcontentloaded instead of full network idle, and reuse one sticky session for a whole flow instead of reloading pages. A full page load can transfer several megabytes, so these steps make a visible difference on a per-GB residential plan.

Ready to plug it in? Get your credentials.

Pick a plan, copy your username and password from the dashboard and run the code above.

  • Pay as you go
  • Instant activation
  • Crypto accepted
  • 24/7 support