playwright-bot-bypass v2.2
A Claude Code skill that wires existing stealth tools β
rebrowser-playwright, real headed Chrome, andundetected-chromedriverβ into a single, agent-ready bundle.
Authorized use only. 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.
What this skill is (and isn't)
It is a packaging + integration layer. The hard stealth work lives in upstream projects (see Credits). What this skill adds:
- π§© A one-import factory β
createStealthBrowser()returns a ready{ browser, page }so an agent doesn't have to rediscover the right combination ofchannel:'chrome'+ headed + rebrowser env var + init script. - π― A verified recipe β which knobs to set and, just as important, which fakes NOT to add. Measured against 8 detectors: the artifact-strip + Runtime-fix pass; the old hand-rolled
navigatorfakes actively hurt (see How It Works). - π Reproducible proof β A/B screenshots + a measured detection-coverage matrix, with honest limits.
- π€ Agent docs β
SKILL.mdso Claude Code can use and reason about it directly.
It is NOT a new stealth engine. It does not author rebrowser-playwright, undetected-chromedriver, or the underlying detection research β it stitches them together and tunes the result.
Installation
npx skills add greekr4/playwright-bot-bypass
What you get
- β Passes fingerprint + automation-framework detectors (sannysoft, rebrowser-detector, deviceandbrowserinfo, browserscan, iphey, creepjs) β measured, 9/9 reproducible
- β Google search without triggering CAPTCHA; public Reddit/YouTube/TikTok/X loads with no bot challenge
- β Real GPU fingerprint, real Chrome UA, genuine PluginArray β from real headed Chrome, not faked in JS
- β One-import factory + human-like helpers (mouse movement, typing delays), cookie persistence, proxy support
- β
Node.js (
rebrowser-playwright) and Python (undetected-chromedriver) paths
A/B: plain Playwright vs this skill
Measured 2026-06-10 (macOS, Apple Silicon). A = default playwright (headless bundled Chromium, no stealth). B = this skill via createStealthBrowser() (headed real Chrome + rebrowser Runtime-fix + Playwright-artifact strip). Same three detectors, same machine.
deviceandbrowserinfo.com β "Are you a bot?"
| A Β· plain Playwright | B Β· this skill |
|---|---|
![]() |
![]() |
β "You are a bot!" (isBot: true) |
β
"You are human!" (isBot: false) |
bot-detector.rebrowser.net β CDP/automation tests (rebrowser's own detector)
| A Β· plain Playwright | B Β· this skill |
|---|---|
![]() |
![]() |
π΄ navigatorWebdriver (= true) |
π’ all green β webdriver false, no __pwInitScripts, no Runtime leak |
bot.sannysoft.com β fingerprint suite
| A Β· plain Playwright | B Β· this skill |
|---|---|
![]() |
![]() |
| Red rows: WebDriver / Chrome / UA = HeadlessChrome / WebGL SwiftShader | All green β real Chrome UA, Apple M2 WebGL, webdriver false |
Honest scope: these are fingerprint + automation-framework detectors, and B passes them cleanly and repeatably (9/9 runs). This does not mean every site is bypassed β IP reputation, behavioral analysis, and login walls (Instagram/Facebook/LinkedIn) are untouched. See SKILL.md β Detection Coverage for the full measured matrix and the one residual leak (
__playwright_builtins__) that no current rebrowser version can strip.
How It Works (3 layers)
The skill's job is to pick the right layers and let them do the work β most evasion is the real browser and the upstream library, not hand-written JS. The skill's own contribution is the integration: the artifact-strip init script, auto-setting the rebrowser env var, and removing the fakes that backfire.
| Layer | Handles |
|---|---|
rebrowser-playwright + Runtime-fix (REBROWSER_PATCHES_RUNTIME_FIX_MODE, auto-set) |
CDP Runtime.enable headless leak; reports webdriver: false |
channel:'chrome' + headed |
real UA, WebGL/GPU, canvas fingerprint, PluginArray, hardware/permission consistency, native navigator.languages via locale |
| artifact strip (one init script) | deletes window.__pwInitScripts / __playwright* (the isPlaywright signature) every navigation |
v2.2 touches nothing on navigator. Removed across v2.1/v2.2 (each faked values inconsistently β net-negative): fake navigator.plugins, canvas noise, hardcoded hardwareConcurrency/deviceMemory, outerWidth/Height offset, the permissions override (Illegal invocation crash), the webdriver delete (made it undefined β a tell), and the navigator.languages getter (own-property + worker-mismatch tells).
Launch arg: --disable-blink-features=AutomationControlled. --no-sandbox is opt-in ({ noSandbox: true }) β a security risk and a bot signal, off by default. Real Chrome via channel: 'chrome'.
Real community sites (single logged-out load, residential IP)
| Site | Result |
|---|---|
| Reddit, YouTube, Pinterest, Threads, X, Quora, TikTok | π’ content fully loaded β no bot challenge / CAPTCHA |
| Instagram, Facebook, LinkedIn | π‘ content behind the normal logged-out login modal β not a bot block / checkpoint / 999 |
None returned a bot challenge β even IG/FB/LinkedIn served the standard human logged-out experience. Caveat: one load each on a clean residential IP; at volume those three enforce datr/999/rate-limits (IP & account problems this skill does not solve).
Quick Start
Node.js (Recommended)
npm init -y && npm install rebrowser-playwright
Using the template (recommended)
import { createStealthBrowser, humanDelay, humanType, simulateMouseMovement } from './scripts/stealth-template.mjs';
const { browser, page } = await createStealthBrowser();
try {
await page.goto('https://example.com');
await simulateMouseMovement(page); // Natural mouse movement
await humanType(page, 'input', 'query'); // Human-like typing
await humanDelay(300, 800);
} finally {
await browser.close();
}
Template options
createStealthBrowser({
headless: false, // Required for stealth (default)
viewport: { width: 1280, height: 800 },
locale: 'ko-KR', // Browser locale (sets navigator.languages + Accept-Language)
storageState: './session.json', // Cookie persistence
proxy: { server: 'http://proxy:8080' }, // Proxy support
noSandbox: false // Opt-in --no-sandbox (Linux root/CI only)
});
Manual setup
// Runtime-fix must be set before importing rebrowser-playwright.
process.env.REBROWSER_PATCHES_RUNTIME_FIX_MODE ??= 'addBinding';
const { chromium } = await import('rebrowser-playwright');
const browser = await chromium.launch({
headless: false,
channel: 'chrome',
args: ['--disable-blink-features=AutomationControlled'] // --no-sandbox is opt-in; it's a bot signal
});
const context = await browser.newContext({ locale: 'ko-KR' }); // sets languages + Accept-Language natively
await context.addInitScript(() => {
// strip Playwright's main-world signature; touch nothing on navigator
for (const k of Object.getOwnPropertyNames(window)) {
if (/^__pw|pwInitScripts|playwright/i.test(k)) { try { delete window[k]; } catch {} }
}
});
const page = await context.newPage();
try {
await page.goto('https://google.com');
} finally {
await browser.close();
}
Python
pip install undetected-chromedriver
import undetected_chromedriver as uc
driver = uc.Chrome() # auto-detects Chrome version
driver.get('https://google.com')
Python
playwright-stealthonly patches at JS level β WebGL still shows SwiftShader. Useundetected-chromedriverinstead.
Test Results
| Environment | bot.sannysoft.com | Google Search | bluer.co.kr |
|---|---|---|---|
| Standard Playwright | Detected | CAPTCHA | 403 |
| This skill (rebrowser + headed Chrome) | Pass | Works | 200 |
| playwright-stealth (Python) | Pass | CAPTCHA | - |
| undetected-chromedriver (Python path) | Pass | Works | - |
Scripts Included
skills/playwright-bot-bypass/
scripts/
stealth-template.mjs # Reusable stealth factory (all examples import this)
bot-detection-test.mjs # Verify bypass at bot.sannysoft.com
examples/
stealth-google-search.mjs # Google search without CAPTCHA
ab-test.mjs # Side-by-side detected vs stealth
stealth-twitter-scrape.mjs # Twitter/X profile scraping
package.json # Dependencies (type: module)
marketplace.json
SKILL.md # Full documentation for Claude Code agents
Requirements
- Node.js 18+ (ESM /
.mjs) - Google Chrome installed (not just Chromium)
- Headed mode (display required β
headless: false)
Troubleshooting
| Problem | Fix |
|---|---|
ERR_MODULE_NOT_FOUND |
Run npm install rebrowser-playwright in your script directory |
| Browser not opening | Verify Chrome: /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version |
| WebGL shows SwiftShader | You're effectively headless / GPU-less. Run headed (headless: false) with channel: 'chrome' on a machine with a real GPU β SwiftShader is the software fallback, not an import issue |
| Still getting detected | Add simulateMouseMovement() and humanDelay() between actions |
| Process hangs | Ensure browser.close() is in a finally block |
Credits
This skill is glue + tuning on top of other people's work. All the heavy lifting belongs to:
- rebrowser-playwright / rebrowser-patches β the patched Playwright that hides the CDP
Runtime.enableleak and reportswebdriver: false. The core of the Node.js path. - undetected-chromedriver (ultrafunkamsterdam) β the Python path.
- Real Google Chrome via Playwright's
channel: 'chrome'β provides the genuine UA / WebGL / canvas / PluginArray that no JS fake can match. - Detection research & test pages used to verify this skill: rebrowser-bot-detector, bot.sannysoft.com, deviceandbrowserinfo.com, browserscan.net, CreepJS, and Antoine Vastel's bot pages.
What's original here is the integration: the createStealthBrowser() factory, the verified v2.2 recipe (the __pwInitScripts strip + auto Runtime-fix, and the decision to remove counter-productive navigator fakes), the measured A/B + coverage matrix, and the agent-facing SKILL.md.
License
MIT





