lonix
lonix

Reputation: 21011

Change navigator.webdriver with Playwright

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?

Upvotes: 1

Views: 4125

Answers (3)

Theo Oliveira
Theo Oliveira

Reputation: 395

Updated version 2024:

await page.addInitScript("delete Object.getPrototypeOf(navigator).webdriver")

Upvotes: 1

George Y.
George Y.

Reputation: 11789

A radical but ultimate method is to hex-edit chrome binary (in ~/.cache/ms-playwright/chromium-<whatever> and replace the webdriver string there with some other nine characters, i.e. aaaaaaaaa.

Upvotes: 2

Charchit Agarwal
Charchit Agarwal

Reputation: 3797

For patching properties in playwright, consider using page.add_init_script instead (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:

await page.add_init_script("delete Object.getPrototypeOf(navigator).webdriver")

The reason page.evaluate seemingly 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 that page.evaluate is not working, which is not true.

Update:

Here's a more robust patch, courtesy of playwright-stealth:

s = """
if (navigator.webdriver === false) {
    // Post Chrome 89.0.4339.0 and already good
} else if (navigator.webdriver === undefined) {
    // Pre Chrome 89.0.4339.0 and already good
} else {
    // Pre Chrome 88.0.4291.0 and needs patching
    delete Object.getPrototypeOf(navigator).webdriver
}
"""

await page.add_init_script(s)    

Upvotes: 4

Related Questions