Introduction to Puppeteer Stealth Mode
By James - Full Stack Developer
When building web scrapers and automation tools, you'll quickly discover that many websites actively detect and block automated browsers. After years of dealing with anti-bot systems, I've learned that vanilla Puppeteer often triggers these detection mechanisms. This is where stealth mode becomes essential !
The Detection Problem
Modern websites use sophisticated techniques to identify automated browsers:
WebDriver Detection: Checking for window.navigator.webdriver
property
Chrome DevTools Protocol: Detecting CDP runtime signatures
Behavioral Analysis: Monitoring mouse movements, typing patterns, and timing
Browser Fingerprinting: Analyzing browser characteristics and inconsistencies
Resource Loading Patterns: Identifying non-human browsing behavior
What is Puppeteer Stealth?
Puppeteer-extra-plugin-stealth is a plugin that applies various evasion techniques to make Puppeteer virtually undetectable. It patches dozens of browser properties and behaviors that typically expose automation tools.
Installation and Setup
npm install puppeteer-extra puppeteer-extra-plugin-stealth
Basic implementation:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
(async () => {
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.goto('https://bot-detection-site.com');
// Your automation code here
await browser.close();
})();
Key Stealth Features
WebDriver Property Masking
The plugin removes the navigator.webdriver
property that immediately flags automated browsers:
// Without stealth: navigator.webdriver = true
// With stealth: navigator.webdriver = undefined
Chrome Runtime Evasion
Stealth mode patches Chrome runtime detection methods that websites use to identify Puppeteer:
// Patches chrome.runtime, chrome.app, and related APIs
// that normally exist in automated Chrome instances
Permission Handling
Normal browsers and automated browsers handle permissions differently. Stealth mode normalizes these behaviors:
// Consistent permission responses for notifications, geolocation, etc.
await page.evaluateOnNewDocument(() => {
Object.defineProperty(Notification, 'permission', {
get: () => 'default'
});
});
Advanced Configuration
For maximum stealth, combine the plugin with additional techniques:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--no-first-run',
'--no-zygote',
'--disable-gpu'
]
});
const page = await browser.newPage();
// Set realistic viewport
await page.setViewport({
width: 1366,
height: 768,
deviceScaleFactor: 1
});
// Set user agent
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
Human-like Behavior Simulation
Beyond technical evasion, implementing human-like patterns significantly reduces detection:
Natural Mouse Movements
// Instead of direct clicks
await page.click('#button');
// Use human-like movements
const button = await page.$('#button');
const box = await button.boundingBox();
await page.mouse.move(box.x + box.width/2, box.y + box.height/2);
await page.mouse.click(box.x + box.width/2, box.y + box.height/2);
Realistic Typing Speed
// Instead of instant typing
await page.type('#input', 'text');
// Use human-like typing
await page.type('#input', 'text', {delay: 100 + Math.random() * 100});
Random Delays
const randomDelay = () => new Promise(resolve =>
setTimeout(resolve, 1000 + Math.random() * 2000)
);
await randomDelay();
await page.click('#next-button');
await randomDelay();
Handling Advanced Detection Systems
Canvas Fingerprinting
Some sites use canvas fingerprinting to detect automation:
await page.evaluateOnNewDocument(() => {
const getImageData = HTMLCanvasElement.prototype.getContext('2d').getImageData;
HTMLCanvasElement.prototype.getContext('2d').getImageData = function(...args) {
const imageData = getImageData.apply(this, args);
// Add slight randomization to canvas data
for (let i = 0; i < imageData.data.length; i += 4) {
imageData.data[i] += Math.floor(Math.random() * 10) - 5;
}
return imageData;
};
});
Request Headers
Maintain consistent headers across requests:
await page.setExtraHTTPHeaders({
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
});
Testing Stealth Effectiveness
Use detection testing websites to verify your setup:
// Test against detection sites
const testSites = [
'https://bot.sannysoft.com/',
'https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html',
'https://arh.antoinevastel.com/bots/areyouheadless'
];
for (const site of testSites) {
await page.goto(site);
await page.screenshot({path: `test-${Date.now()}.png`});
// Analyze results
}
Performance Considerations
Stealth mode adds overhead. For large-scale operations:
Pool Browser Instances: Reuse browsers across multiple pages
Selective Stealth: Only apply stealth when necessary
Monitor Resource Usage: Stealth plugins consume additional memory
Load Balancing: Distribute requests across multiple instances
Common Pitfalls
Over-Engineering
Don't apply every possible stealth technique. Start minimal and add layers only when detection occurs.
Ignoring Rate Limits
Even perfect stealth won't help if you're making requests too quickly. Implement proper rate limiting.
Static Patterns
Avoid predictable timing and behavior patterns. Randomization is crucial.
When to Use Stealth Mode
Web Scraping: Essential for sites with anti-bot protection
Automated Testing: When testing anti-fraud systems
Market Research: Gathering competitive intelligence
Price Monitoring: Tracking competitor pricing
Ethical Considerations
Always respect robots.txt and terms of service. Stealth mode should be used for legitimate automation needs, not to circumvent security measures maliciously.
Conclusion
Stealth mode transforms Puppeteer from a easily-detected automation tool into a sophisticated browser that can navigate modern anti-bot systems. The key is combining technical evasion with human-like behavioral patterns.
Start with the basic stealth plugin and gradually add complexity as needed. Test regularly against detection systems and adapt your approach as anti-bot technology evolves. With proper implementation, you can build robust automation systems that reliably access protected content.