CAPTCHAs are everywhere. They sit between your Puppeteer script and the data you need, and Puppeteer reCAPTCHA detection is getting harder to avoid.
The good news: there are reliable ways to handle them. This guide covers why Puppeteer triggers CAPTCHAs, which** **bypass CAPTCHA methods actually work, and how to set them up. You’ll find options for reCAPTCHA v2, v3, hCaptcha, and image-based challenges.
Bypass Puppeteer CAPTCHA: the tutorial
A Puppeteer CAPTCHA solver is one of the most effective ways to do that. Puppeteer is a Node.js library with a clean API for controlling Chrome and Chromium through the DevTools Protocol. You can run it in full browser mode instead of headless, which helps avoid detection, and pair it with options like waitUntil to handle dynamic content reliably.
Why Puppeteer alone isn’t enough
Run Puppeteer against a CAPTCHA-protected site without any bypass method, and the site will flag you fast. It detects automated access and responds with a block screen or a CAPTCHA challenge.
Let’s test this.
- First, make sure Node.js is installed. Then create a new project and install Puppeteer:
npm i puppeteer
- Import the Puppeteer library in your Node.JS file.
const puppeteer = require('puppeteer');
- Create a new browser instance in headless browser mode and open a new page as shown below.
(async () => {
// Create a browser instance
const browserObj = await puppeteer.launch();
// Create a new page
const newpage = await browserObj.newPage();
- Since we need a screenshot from a desktop viewport, set the size with.
// Set the width and height of viewport
await newpage.setViewport({ width: 1920, height: 1080 });
The setViewPort() method sets the size of the webpage, but you can adjust it according to your device’s requirements.
- After that, navigate to a CAPTCHA-protected URL and take a screenshot. The example here uses Oxylabs’ Scraping Sandbox. Close the browser object when done.
const url = 'https://sandbox.oxylabs.io/products';
// Open the required URL in the newpage object
await newpage.goto(url);
await newpage.waitForNetworkIdle(); // Wait for network resources to fully load
// Capture screenshot
await newpage.screenshot({
path: 'screenshot.png',
});
// Close the browser object
await browserObj.close();
})();
This is what the complete bypass CAPTCHA code looks like:
const puppeteer = require('puppeteer');
(async () => {
const browserObj = await puppeteer.launch();
const newpage = await browserObj.newPage();
await newpage.setViewport({ width: 1920, height: 1080 });
const url = 'https://sandbox.oxylabs.io/products';
await newpage.goto(url);
await newpage.waitForNetworkIdle();
await newpage.screenshot({
path: 'screenshot.png',
});
await browserObj.close();
})();
Note: If you see a block screen or a CAPTCHA, the site has detected bot activity and has cut off access.
Bypass CAPTCHA with Puppeteer-stealth
The Stealth plugin extends Puppeteer with a set of techniques that mask the signs of automated browser control. It makes headless access look human enough that most sites can’t tell the difference, which means no CAPTCHA, no block screen, and full access to protected content.
Note: All Puppeteer CAPTCHA bypass methods in this guide are for educational purposes only.
- To get started, install the puppeteer-extra + puppeteer-extra-plugin-stealth packages:
npm install puppeteer-extra-plugin-stealth puppeteer-extra
- Then, import the following required libraries in your Node.JS file:
const puppeteerExtra = require('puppeteer-extra');
const Stealth = require('puppeteer-extra-plugin-stealth');
puppeteerExtra.use(Stealth());
- Create the browser object in headless mode. Navigate to the URL and take a screenshot with Puppeteer.
(async () => {
const browserObj = await puppeteerExtra.launch();
const newpage = await browserObj.newPage();
await newpage.setViewport({ width: 1920, height: 1080 });
await newpage.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
);
await newpage.goto('https://sandbox.oxylabs.io/products');
await newpage.waitForNetworkIdle(); // Wait for network resources to fully load
await newpage.screenshot({ path: 'screenshot_stealth.png' });
await browserObj.close();
})();
The setUserAgent method makes your headless browser send a real browser’s User-Agent string. Most anti-bot systems check this header, but setting a common one stops them from flagging your requests as automated.
Here is what our complete bypass CAPTCHA script looks like:
const puppeteerExtra = require('puppeteer-extra');
const Stealth = require('puppeteer-extra-plugin-stealth');
puppeteerExtra.use(Stealth());
(async () => {
const browserObj = await puppeteerExtra.launch();
const newpage = await browserObj.newPage();
await newpage.setViewport({ width: 1920, height: 1080 });
await newpage.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
);
await newpage.goto('https://sandbox.oxylabs.io/products');
await newpage.waitForNetworkIdle(); // Wait for network resources to fully load
await newpage.screenshot({ path: 'screenshot_stealth.png' });
await browserObj.close();
})();
If your screenshot shows the actual page content, the stealth setup worked — your bypass CAPTCHA script got through successfully.
Bypass CAPTCHA with Web Unblocker & Node.JS
All that said, Stealth isn’t bulletproof — sites with more sophisticated anti-bot systems can still catch it.
For those cases, Oxylabs’ Web Unblocker or Decodo’s Site Unblocker are excellent alternatives worth looking into.
In this example, we’ll be using the Oxylabs solution to handle CAPTCHA, together with Node.JS.
Web Unblocker uses AI to navigate CAPTCHA and reCAPTCHA challenges and pull public web data from complicated websites. It handles all the potential challenges for you:
- Proxy management
- Browser fingerprint generation
- Automatic retries
- Session maintenance
- JavaScript rendering
To start, send a basic request with no special options — Web Unblocker will pick the fastest proxy for us, add the required headers, and return the response body.
- Start by installing node-fetch and HttpsProxyAgent first:
npm install node-fetch https-proxy-agent
2. Sign up to Oxylabs to get your API credentials. Then open your package.json file and add “type”: “module” — for example:
{
"type": "module",
"dependencies": {
"https-proxy-agent": "^7.0.4",
"node-fetch": "^3.3.2",
"puppeteer": "^22.6.5",
"puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2"
}
}
- Since the latest version of node-fetch is ESM-only, you can’t load it with require(). Import the required modules in your JS file using the import syntax as shown below. The fs library can help save the response in an HTML file.
import fetch from 'node-fetch';
import HttpsProxyAgent from 'https-proxy-agent';
import fs from 'fs';
- Write your user credentials and set up a proxy using HttpsProxyAgent:
const username = '<Your-username>';
const password = '<Your-password>';
(async () => {
const agent = new HttpsProxyAgent.HttpsProxyAgent(
`@unblock.oxylabs.io:60000`">http://${username}:${password}@unblock.oxylabs.io:60000`
);
- Next, set the URL and issue a fetch request.
// Ignore the certificate
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;
const response = await fetch('https://ip.oxylabs.io/', {
method: 'get',
agent: agent,
});
- Setting NODE_TLS_REJECT_UNAUTHORIZED to 0 tells Node.js to skip SSL/TLS certificate verification, which is required when using Web Unblocker.
Finally, convert the response to text and save it as an HTML file:
const resp = await response.text();
fs.writeFile('result.html', resp.toString(), (err) => {
if (err) throw err;
console.log('Result saved to result.html');
});
})();
Voilà! Here’s the complete script to navigate CAPTCHA with Web Unblocker:
import fetch from 'node-fetch';
import HttpsProxyAgent from 'https-proxy-agent';
import fs from 'fs';
const username = '<Your-username>';
const password = '<Your-password>';
(async () => {
const agent = new HttpsProxyAgent.HttpsProxyAgent(
`@unblock.oxylabs.io:60000`">http://${username}:${password}@unblock.oxylabs.io:60000`
);
// Ignore the certificate
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;
const response = await fetch('https://ip.oxylabs.io/', {
method: 'get',
agent: agent,
});
const resp = await response.text();
fs.writeFile('result.html', resp.toString(), (err) => {
if (err) throw err;
console.log('Result saved to result.html');
});
})();
Thanks to Web Unblocker, we were able to handle CAPTCHA by simply not allowing it to even load.
Final word
Puppeteer alone won’t cut it when it comes to complex websites. But combining it with Puppeteer-Stealth or Web Unblocker gives you a reliable path through most Puppeteer CAPTCHA challenges — from reCAPTCHA v2 and v3 to hCaptcha and image-based tests.
Start with Stealth for lightweight projects. For tougher targets, Web Unblocker handles the heavy lifting so you can focus on the data.

Comments
Loading comments…