Web Scraping & Automation

Puppeteer Stealth + Proxies: Making Headless Chrome Look Human

Why Puppeteer gets detected even with residential proxies, how puppeteer-extra-plugin-stealth helps, matching timezone and language to your proxy, and the limits of stealth against modern bot protection.

By Team of Monkeys Editorial Updated 5 min read Affiliate disclosure

This guide contains affiliate links to Geonode. If you buy through them we may earn a commission, at no extra cost to you.

Good proxies, still blocked?

A common story: you switch your Puppeteer scraper from datacenter to premium residential proxies, and you still see CAPTCHAs and "Access denied". That's because modern bot protection scores much more than the IP. It inspects the browser itself, and default headless Chrome has many tell-tale signs.

This guide covers how to reduce those signs and how to align the browser with the proxy. It also explains the limits: stealth helps, but it's not a guarantee.

What gives Puppeteer away

  • navigator.webdriver set to true in automated Chrome.
  • Headless indicators. Older headless modes exposed differences in user agent ("HeadlessChrome"), plugins, permissions, rendering and APIs. Chrome's newer headless mode is much closer to headful Chrome, but differences remain.
  • Default viewport of 800x600, uncommon on real devices.
  • Missing or inconsistent properties such as languages, plugins, WebGL vendor.
  • CDP side effects that sophisticated scripts can probe.
  • Mismatches with the proxy: timezone, language and geolocation that don't fit the IP.
  • Behaviour: no mouse movement, instant form filling, perfectly regular timing.
  • TLS/HTTP2 fingerprint (Chrome's is genuine, which is an advantage of real browsers over HTTP libraries).

See browser fingerprinting and proxies.

puppeteer-extra and the stealth plugin

puppeteer-extra wraps Puppeteer with a plugin system. The stealth plugin applies a set of evasions for common detection checks:

javascript
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';

puppeteer.use(StealthPlugin());

const browser = await puppeteer.launch({
  headless: true,
  args: ['--proxy-server=http://gate.example.com:7777'],
});
const page = await browser.newPage();
await page.authenticate({ username: 'customer-USER-country-us-session-x1', password: 'PASS' });
await page.goto('https://example.com');

It helps against basic and intermediate checks. Against top-tier bot protection, which is updated continuously, public evasions are often detected. Be aware that the plugin itself is no longer actively developed: its latest release (2.11.2) dates from March 2023 and its repository hasn't changed since mid-2024, so treat it as a baseline rather than a current fix, and test regularly.

Align the browser with the proxy

If your proxy exits in Chicago, your browser should look like it's in Chicago:

javascript
await page.emulateTimezone('America/Chicago');
await page.setExtraHTTPHeaders({ 'Accept-Language': 'en-US,en;q=0.9' });
await page.setViewport({ width: 1366, height: 768 });

You can also launch with a matching language flag, for example --lang=en-US. For geolocation API checks:

javascript
const ctx = browser.defaultBrowserContext();
await ctx.overridePermissions('https://example.com', ['geolocation']);
await page.setGeolocation({ latitude: 41.8781, longitude: -87.6298 });

Look up the proxy's location first (request an IP-info endpoint through it) and set these values dynamically. See geo-targeted proxies.

Prevent WebRTC leaks

WebRTC can reveal your real IP even through a proxy. Chromium flags such as --force-webrtc-ip-handling-policy=disable_non_proxied_udp reduce the risk. See WebRTC leaks and proxies.

Behave more like a person

  • Add small random delays between actions.
  • Move the mouse and scroll before clicking.
  • Type with per-key delays (page.type(selector, text, { delay: 50 + Math.random() * 100 })).
  • Don't open dozens of pages per second from one IP.

Proxy tip: Want to skip proxy management on some targets? Geonode offers both raw proxies and a Scraper API that returns HTML or Markdown with optional JavaScript rendering. We compare the two approaches in using Geonode with Puppeteer.

Headful mode and real Chrome

Some teams run headful Chrome (with a virtual display on servers) or use the user's installed Chrome via executablePath to reduce differences. This costs more resources but can raise success rates on strict sites.

Know when to stop fighting

If a target is protected by aggressive enterprise bot management and you're spending days on evasions, compare the cost with a web unblocker or scraping API.

A practical hardening checklist

  • [ ] Recent Puppeteer and Chrome versions
  • [ ] Stealth plugin (or equivalent evasions), kept updated
  • [ ] Realistic viewport and device scale factor
  • [ ] Timezone and language matched to the proxy exit
  • [ ] WebRTC restricted to proxied routes
  • [ ] Human-like pacing and interaction where relevant
  • [ ] Sticky session per browser context
  • [ ] Cookies persisted per identity when appropriate
  • [ ] Block detection and rotation on challenge

Testing your setup

Use public browser fingerprint and bot-detection test pages through your proxy to see what signals your setup exposes. Compare results with a normal Chrome browser on the same machine. Differences highlight what to fix. Re-test after updates; Chrome and evasion libraries change often.

Matching the proxy type to stealth effort

Target strictnessProxyStealth effort
LenientDatacenterMinimal
ModerateResidentialStealth plugin + locale matching
StrictResidential or mobileFull hardening, headful mode, human-like behaviour
Very strictUnblocker or APIOutsourced

See Puppeteer proxies and headless browser proxies.

Beyond the stealth plugin

With the stealth plugin effectively frozen, teams that need more than baseline evasion usually move to one of these approaches:

  • Real Chrome, headful. Launch the installed Chrome (channel: 'chrome') in headful mode, on a virtual display on Linux servers. It removes a whole class of headless differences.
  • New headless mode. Modern headless Chrome is the same browser as headful Chrome, which closes many of the gaps the stealth plugin was written for. See headless browser proxies.
  • Antidetect browsers with automation APIs, which manage fingerprints per profile and pair each profile with its own proxy. See antidetect browser proxies.
  • Patched automation stacks. Community forks and patches target leaks that come from the DevTools protocol itself, which no page-level JavaScript patch can fully hide. Check how actively each one is maintained before depending on it.
  • Not using a browser at all. For many targets, an HTTP client with a browser-like TLS fingerprint is cheaper and harder to tell apart than a patched browser.

Whatever you choose, test regularly against the protection your targets actually use, keep the browser's timezone, language and locale aligned with the proxy, and accept that some sites don't want automated visitors. For the signals involved, see browser fingerprinting and proxies; for when to stop, see ethical web scraping.

Key takeaways

  • Residential proxies fix IP signals; stealth techniques fix browser signals. Protected sites usually require both.
  • puppeteer-extra-plugin-stealth defeats many common checks but not top-tier bot management.
  • Match timezone, language and geolocation to the proxy exit, and restrict WebRTC.
  • Human-like pacing and interaction help on interactive pages.
  • When evasion work becomes expensive, compare with unblockers or scraping APIs. See web unblocker proxies.

FAQ

Does the stealth plugin make Puppeteer undetectable?

No. It defeats many common checks but not all, and bot protection vendors update continuously.

Do I still need residential proxies with stealth?

On protected sites, yes. Stealth fixes browser signals; proxies fix IP signals. You usually need both.

Is Playwright better at stealth than Puppeteer?

Both drive real browser engines and face similar detection. See Playwright proxies.

Affiliate disclosure: Team of Monkeys is a Geonode affiliate. Links and banners marked as sponsored, and links to Geonode in the text, use our referral link, and we may earn a commission if you buy through them, at no extra cost to you. Our explanations and comparisons are written to be useful whichever provider you choose.

Editorial note: Proxy providers change their pools, features and prices often, so treat any figures here as typical ranges at the time of writing and confirm current terms with the provider before you buy.