I'm using Playwright with Chrome.
In other tools, one can easily change navigator.webdriver like so:
Object.defineProperty(navigator, 'webdriver', { get: () => false });
In Playwright + Chrome (using .NET bindings, but same idea in Node / Python), I tried:
// attempt 1
await context.AddInitScriptAsync("""
Object.defineProperty(navigator, 'webdriver', { get: () => false });
""");
// attempt 2
await page.EvaluateAsync("""
Object.defineProperty(navigator, 'webdriver', { get: () => false });
""");
// attempt 3
await page.EvaluateAsync("""
delete Object.getPrototypeOf(navigator).webdriver;
Object.defineProperty(navigator, 'webdriver', { get: () => false });
""");
// attempt 4
await page.EvaluateAsync("""
const newProto = navigator.__proto__;
delete newProto.webdriver;
navigator.__proto__ = newProto;
""");
In all cases the browser still reports that it is using webdriver (e.g. here).
How do I do this with Playwright?
For patching properties in playwright, consider using
page.add_init_scriptinstead (or it's equivalent in other languages, this is for python). This is because the script you add through this method will automatically be called every time the page is navigated or whenever a child frame is attached, in their respective contexts. This will save you the hassle of doing it manually.Example:
The reason
page.evaluateseemingly does not work has to do with the fact that it is run after the page has navigated (calling the method before that does not make sense because the changes will be overwritten after navigation anyway). Since the webpage cannot react to changes you do after it has already completed its tests, it makes it seem thatpage.evaluateis not working, which is not true.Update:
Here's a more robust patch, courtesy of
playwright-stealth: