Codementor Events

Introduction to Puppeteer Stealth Mode

Published May 27, 2025Last updated May 28, 2025

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.

Discover and read more posts from Will James
get started