Skip to content
Automation
Skill

/playwright-bot-bypass

This skill should be used when the user asks to "bypass bot detection", "avoid CAPTCHA", "stealth browser automation", "undetected playwright", "bypass Google bot check", "rebrowser-playwright", or needs to automate websites that detect and block bots.

From plugin
playwright-bot-bypass
1841 skill
Install
$ npx -y skills add greekr4/playwright-bot-bypass --skill playwright-bot-bypass --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/playwright-bot-bypass

Context preview

The summary Claude sees to decide when to auto-load this skill.

This skill should be used when the user asks to "bypass bot detection", "avoid CAPTCHA", "stealth browser automation", "undetected playwright", "bypass Google bot check", "rebrowser-playwright", or needs to automate websites that detect and block bots.

SKILL.md

playwright-bot-bypass.SKILL.md
name: playwright-bot-bypass
description: This skill should be used when the user asks to "bypass bot detection", "avoid CAPTCHA", "stealth browser automation", "undetected playwright", "bypass Google bot check", "rebrowser-playwright", or needs to automate websites that detect and block bots.
version: 2.2.0

Playwright Bot Bypass

Reduce bot detection using rebrowser-playwright + real headed Chrome. Passes fingerprint checkers (bot.sannysoft.com, areyouheadless) and avoids triggering CAPTCHAs on Google. **Not** a guaranteed bypass for CDP/runtime-aware enterprise bot managers — see "Detection Coverage" for measured results.

> **Authorized use only.** This is for QA, accessibility testing, and research on sites you own or are permitted to test. Respect each site's Terms of Service, `robots.txt`, and applicable law. Do not use it to bypass paywalls, abuse rate limits, or scrape against a site's stated wishes.

How Detection Is Defeated (and by which layer)

Evasion comes from **three** layers, not one — most of it is the real browser, not hand-written JS:

| Detection Point | Standard Playwright (headless) | Defeated by | |-----------------|--------------------------------|-------------| | CDP / `Runtime.enable` leak | Present (headless tell) | **rebrowser + `REBROWSER_PATCHES_RUNTIME_FIX_MODE`** (auto-set) | | `window.__pwInitScripts` (`isPlaywright`) | Present | **artifact strip** (init script deletes it every nav) | | `navigator.webdriver` | `true` | **rebrowser** (reports `false`; we do NOT delete it — `undefined` is itself a tell) | | WebGL Renderer | SwiftShader (software) | **`channel:'chrome'` + headed mode** (real GPU) | | User Agent | Contains "HeadlessChrome" | **`channel:'chrome'`** (real Chrome UA) — no JS override | | Canvas fingerprint | Software-rendered tell | **headed real Chrome** (genuine GPU canvas) — no JS noise | | `navigator.plugins` | Empty array | **headed real Chrome** (genuine PluginArray) — no JS fake | | `navigator.languages` | `['en-US']` only | **`locale` option** (native, worker-consistent — no JS getter) |

> **Why so little hand-written JS?** Across v2.1/v2.2 the old fake-PluginArray, canvas-noise, hardcoded-`hardwareConcurrency`, permissions-override, `webdriver` delete, and `navigator.languages` getter were all removed — every one created a *detectable inconsistency* (own-property tells, worker mismatches, `undefined` webdriver, an `Illegal invocation` crash). v2.2 keeps exactly **two** active measures: strip Playwright's `__pwInitScripts` artifact, and enable rebrowser's Runtime-fix. Everything else is the genuine, self-consistent real browser. Less faking = more consistent = harder to detect.

Prerequisites

  • **Node.js 18+** with ESM support (`.mjs` files)
  • **Google Chrome** installed (not just Chromium)
  • **Headed mode** required (`headless: false`) — no display = no stealth

Verify Chrome is installed:

# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --version
# Linux
google-chrome --version

Quick Start

1. Install

npm init -y && npm install rebrowser-playwright

2. Create `stealth-test.mjs`

import os from 'node:os';
import path from 'node:path';

// Enable rebrowser's Runtime.enable fix BEFORE importing the library.
process.env.REBROWSER_PATCHES_RUNTIME_FIX_MODE ??= 'addBinding';
const { chromium } = await import('rebrowser-playwright');

const browser = await chromium.launch({
  headless: false,                                  // headed = real GPU/canvas
  channel: 'chrome',                                // real Chrome = real UA/WebGL/plugins
  args: ['--disable-blink-features=AutomationControlled']
});

// `locale` sets navigator.languages + Accept-Language natively & consistently.
const context = await browser.newContext({ locale: 'ko-KR' });

// The ONLY init script: strip Playwright's main-world signature. Touch NOTHING
// on navigator — the real browser's values are already genuine & consistent.
await context.addInitScript(() => {
  for (const k of Object.getOwnPropertyNames(window)) {
    if (/^__pw|pwInitScripts|playwright/i.test(k)) {
      try { delete window[k]; } catch {}
    }
  }
  if (!window.chrome) window.chrome = {};
});

const page = await context.newPage();

try {
  await page.goto('https://bot.sannysoft.com', { waitUntil: 'networkidle' });
  const out = path.join(os.tmpdir(), 'stealth-test.png');
  await page.screenshot({ path: out });
  console.log(`Screenshot saved: ${out}`);
} finally {
  await browser.close();
}

3. Run

node stealth-test.mjs

Using the Template (Recommended)

The `scripts/stealth-template.mjs` provides a reusable factory with all patches pre-applied:

import { createStealthBrowser, humanDelay, humanType, simulateMouseMovement } from './scripts/stealth-template.mjs';

const { browser, page } = await createStealthBrowser();

try {
  await page.goto('https://example.com');

  // Human-like mouse movement (avoids Cloudflare Turnstile)
  await simulateMouseMovement(page);

  // Human-like typing instead of instant fill
  await humanType(page, 'input[name="q"]', 'search query');
  await humanDelay(300, 800);
} finally {
  await browser.close();
}

Template Options

const { browser, context, page } = await createStealthBrowser({
  headless: false,             // Required for stealth (default)
  viewport: { width: 1280, height: 800 },  // Default
  locale: 'ko-KR',            // Browser locale (default)
  userAgent: null,             // Custom UA (optional; default = real Chrome UA)
  storageState: './session.json',  // Cookie persistence (optional)
  proxy: { server: 'http://proxy:8080' },  // Proxy (optional)
  noSandbox: false             // Opt-in --no-sandbox (Linux root/CI only; it's a bot signal)
});

// Save session for reuse
import { saveSession } from './scripts/stealth-template
Read more
Ships withplaywright-bot-bypass

Undetected browser automation that passes 8/8 bot detectors — with a real headed Chrome instead of fragile JS fakes. It's glue + tuning over rebrowser-playwright and undetected-chromedriver, shipped as a one-import createStealthBrowser() and an agent skill.

Get the whole plugin
Stats
188
Stars
13
Forks
Active
Maintenance
JavaScript
Language
MIT
License
25d ago
Last commit
6mo ago
Created

Repo: greekr4/playwright-bot-bypass