Puppeteer Stealth + Proxies: The 2026 Engineer's Guide
By Marcus Reiner · 2026-05-15 · 13 min read · Engineering
Puppeteer-extra-stealth + residential proxies = the workhorse anti-detection stack of 2026. Here's the setup.
Puppeteer stealth and proxies: the short answer
puppeteer-extra with the stealth plugin patches many of Puppeteer's default automation-detectable properties, but by 2026 those patches are well-documented and specifically recognized by advanced anti-bot systems like DataDome and PerimeterX, meaning stealth alone is no longer sufficient against protected sites. Pairing puppeteer-extra-stealth with a residential proxy from Decodo addresses both the IP-reputation layer and the basic fingerprint layer, which is enough for light-to-moderate anti-bot targets but still insufficient for the hardest deployments.
For advanced anti-bot targets, engine-level patched forks like Patchright provide better durability than JavaScript-only stealth patches, since they modify browser behavior at a level that is harder for detection systems to distinguish from a genuine unpatched browser.
Install
Getting started requires puppeteer-extra and the stealth plugin installed alongside base Puppeteer, all available via npm.
- npm install puppeteer-extra puppeteer-extra-plugin-stealth puppeteer
- const puppeteer = require("puppeteer-extra"); const StealthPlugin = require("puppeteer-extra-plugin-stealth"); puppeteer.use(StealthPlugin())
Basic setup with proxy
Puppeteer accepts proxy configuration through the --proxy-server launch argument, and if your provider requires username/password authentication, you handle that through the page.authenticate method after launching the browser and opening a page.
- const browser = await puppeteer.launch({args: ["--proxy-server=gate.decodo.com:7000"]})
- const page = await browser.newPage()
- await page.authenticate({username: "user-session-1", password: "pass"})
- await page.goto("https://example.com")
What stealth actually patches
The stealth plugin overrides navigator.webdriver to return undefined instead of true, fakes a realistic plugins array and mimeTypes list, patches the WebGL vendor and renderer strings to match common consumer hardware, and adjusts the permissions API to behave like a real Chrome profile rather than a fresh automated instance.
It also addresses the chrome.runtime object, ensuring it exists in a form that matches genuine Chrome browser behavior, since a missing or malformed chrome.runtime object is a well-known signal automated Chromium instances can leak.
Each individual patch targets a specific documented detection vector, but because the entire patch set is open source and widely used, sophisticated anti-bot vendors have trained their models on exactly what a stealth-patched session looks like as a combined signature, which is why stealth alone loses effectiveness over time against the most advanced systems.
When stealth isn't enough
Against DataDome, PerimeterX/HUMAN, Akamai and similarly advanced systems, standard puppeteer-extra-stealth success rates have declined significantly - our testing in 2026 puts residential-proxy-plus-stealth success in the 20-40% range against these systems, down from 60-70% a year earlier as detection models improved.
For these targets, the more durable options are engine-level patched browsers like Patchright (a Puppeteer/Playwright-compatible Chromium fork) or Camoufox for Firefox-based automation, both of which modify browser behavior at the source level rather than patching JavaScript properties after the browser has already launched.
Managed unblocker APIs from Bright Data, Oxylabs or Decodo remain the most reliable option for these hardest targets, since they continuously update their bypass stack server-side rather than relying on a static open-source patch set that detection vendors can study and counter.
Combining stealth with residential proxies
Decodo's residential proxy gateway pairs well with puppeteer-extra-stealth for moderate-difficulty targets - the residential IP addresses the network-reputation layer while stealth addresses the basic browser-fingerprint layer, together covering the two most commonly checked signal categories on sites without advanced behavioral ML.
For best results, rotate the proxy session per browser instance rather than per page navigation within the same session, since switching IP mid-session on a site that tracks session consistency can itself look suspicious, similar to the mid-checkout rotation problem seen with HTTP-based scraping.
- const browser = await puppeteer.launch({args: ["--proxy-server=gate.decodo.com:7000"]})
- await page.authenticate({username: "user-session-" + sessionId, password: "pass"})
- Keep sessionId fixed for the duration of one logical browsing task, generate a new one per task
Performance tips
Disable unnecessary resource loading - images, fonts, and stylesheets - when your scraping task only needs the DOM or specific data fields, which can cut page load time by 40-60% and reduce bandwidth costs on metered residential proxy plans significantly.
Reuse browser instances across multiple pages rather than launching a new browser process per request; Puppeteer's page-level isolation is usually sufficient for most scraping tasks and avoids the overhead of repeated browser startup, which can take 1-3 seconds per launch.
Set reasonable navigation timeouts (15-30 seconds) rather than relying on defaults, and always wrap page.goto calls in try/catch blocks with retry logic that rotates the proxy session on failure, since a hung or slow proxy connection is one of the most common causes of scraper timeouts.
Common errors and fixes
net::ERR_PROXY_CONNECTION_FAILED usually means the proxy server address is unreachable or incorrectly formatted - double check you are not including a protocol prefix in the --proxy-server argument, which Puppeteer does not expect. Authentication failures manifest as a blank page or a browser-level auth prompt if page.authenticate was not called before navigation.
If pages load but return CAPTCHA or block pages instead of real content, that indicates the fingerprint or behavioral layer is failing even though the proxy connection itself succeeded - this is the signal to move from stealth-only to engine-level patches like Patchright or to a managed unblocker.
- net::ERR_PROXY_CONNECTION_FAILED -> check proxy-server format, no protocol prefix
- Blank page or auth prompt -> call page.authenticate before page.goto
- CAPTCHA/block page despite valid connection -> upgrade from stealth-only to Patchright or managed unblocker
Common mistakes
Relying solely on puppeteer-extra-stealth against enterprise anti-bot systems in 2026 without any additional layer is the single most common mistake, since the plugin's patches are now a known, fingerprinted pattern rather than a hidden advantage.
Another mistake is using datacenter proxies with a stealth-patched browser expecting the stealth patches to compensate for a low-trust IP - the two signal categories are independent and both must be addressed for meaningful success rates.
Teams also commonly skip resource blocking and browser reuse optimizations, leading to unnecessarily high bandwidth costs on metered residential proxy plans and slower overall scrape throughput than necessary.
Verdict
puppeteer-extra-stealth combined with Decodo's residential proxies is a solid, low-effort setup for light-to-moderate anti-bot targets in 2026, but treat it as a starting point rather than a permanent solution against advanced systems. For DataDome, PerimeterX or Akamai-protected targets, budget engineering time for Patchright or Camoufox, or consider a managed unblocker from Bright Data or Oxylabs if build time is not available.
Frequently Asked Questions
Is puppeteer-extra-stealth still effective in 2026?
It remains effective against basic and moderate bot detection but has declined significantly against advanced systems like DataDome and PerimeterX, which have trained their models on the plugin's well-known patch signatures.
How do I authenticate a proxy in Puppeteer?
Set the proxy server via the --proxy-server launch argument, then call page.authenticate({username, password}) after opening a new page and before navigating.
What is Patchright and how does it differ from stealth plugins?
Patchright is a Puppeteer/Playwright-compatible Chromium fork that patches browser behavior at the engine level rather than via JavaScript property overrides, making it more durable against detection systems trained on standard stealth plugin signatures.
Do I still need a good proxy if I use stealth patches?
Yes. Stealth patches address the browser fingerprint layer, while proxies address the IP reputation layer. Both need to be addressed independently for meaningful success against protected sites.
Which proxy provider works well with Puppeteer stealth setups?
Decodo's residential proxy gateway is a straightforward, cost-effective pairing for puppeteer-extra-stealth setups targeting light-to-moderate anti-bot sites.