Support anti-bot detection evasion (navigator.webdriver, launch args) #56
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Sites like archive.ph detect Playwright-controlled browsers and return HTTP 429 or serve captcha pages instead of content. The primary detection vector is
navigator.webdriver === true, which Playwright sets on all controlled browsers by default.Currently
BrowserOptionsdoesn't expose any way to mitigate this, so consumers have no recourse when a site blocks automated access.Proposed API Changes
1. Expose browser launch arguments
Add a
LaunchArgs []stringfield toBrowserOptionsso consumers can pass flags like:This would be passed through to
playwright.BrowserTypeLaunchOptions.Args.2. Expose context init scripts
Add an
InitScripts []stringfield toBrowserOptionsto allow injecting JavaScript before any page loads. This enables overridingnavigator.webdriverand other detectable properties:This would be passed through to
browserContext.AddInitScript().3. Optional: Stealth mode preset
A convenience
Stealth boolfield that applies common anti-detection measures automatically:--disable-blink-features=AutomationControllednavigator.webdrivernavigator.pluginsandnavigator.mimeTypeswindow.chromeruntime propertieswindow.outerWidth/outerHeightto match viewportContext
This came up in steve/mort#687 — the summary system's headless browser gets 429'd by archive.ph. The interactive browser (same Playwright, same user agent) works fine when a human is controlling it, but the
webdriverproperty gives away the automation.Detection Vectors (for reference)
navigator.webdrivertruetrueundefinedwindow.outerWidth0navigator.plugins.length003+window.chromeThe most impactful single change would be #1 (launch args) since
--disable-blink-features=AutomationControlledalone fixes thewebdriverproperty for Chromium and is the most commonly checked signal.Starting work on this issue. My plan:
LaunchArgs []string,InitScripts []string, andStealth *boolfields toBrowserOptionsmergeOptionsto handle the new fieldsinitBrowserto pass launch args, apply stealth presets, and inject init scripts into the browser contextStealthtotruein bothNewBrowserandNewInteractiveBrowser--no-stealthCLI flag to the browser flags packageWork complete. Merged via PR #57.
What was implemented:
Stealth *boolfield onBrowserOptions— defaults totrueinNewBrowserandNewInteractiveBrowserLaunchArgs []string— custom browser launch arguments passed to PlaywrightInitScripts []string— JavaScript injected into every browser context before page scriptsnavigator.webdriveroverride, plugin/mimeType spoofing,window.chromestub,outerWidth/outerHeightfix, Chromium--disable-blink-features=AutomationControlled--no-stealthflag for command-line tools