Skip to content

fix(stealth): use Stealth class from playwright-stealth 2.x#1960

Open
NaabZer wants to merge 1 commit intounclecode:developfrom
NaabZer:bugfix/stealth-import-mismatch
Open

fix(stealth): use Stealth class from playwright-stealth 2.x#1960
NaabZer wants to merge 1 commit intounclecode:developfrom
NaabZer:bugfix/stealth-import-mismatch

Conversation

@NaabZer
Copy link
Copy Markdown

@NaabZer NaabZer commented May 7, 2026

Summary

Fixes #1959.

StealthAdapter._check_stealth_availability imported stealth_async / stealth_sync from playwright_stealth, which 2.x doesn't expose. Replaced with the Stealth class — apply_stealth_async accepts Page or BrowserContext, so existing call sites are unchanged.

Changes

  • crawl4ai/browser_adapter.py — Swap the broken function-style imports for Stealth().apply_stealth_async(page).

Test plan

Ran the issue's repro against develop (broken) and this branch (fixed), with enable_stealth=False as the control:

version enable_stealth=False enable_stealth=True
develop navigator.languages: ["en-US"] navigator.languages: ["en-US"] ← stealth=True is a no-op
this branch navigator.languages: ["en-US"] navigator.languages: ["en-US","en"]Stealth init script applied

The added "en" is Stealth()'s default navigator_languages_override — proves the init script is now being injected. On Chromium 147 headless-shell most other classic signals (navigator.webdriver, chrome.csi/loadTimes, etc.) are already masked by the browser itself, so this is the clearest single-property A/B differentiator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant