playwright-ghost
v0.16.0
Published
Playwright with plugins to be a ghost.
Maintainers
Readme
Playwright-ghost
Playwright-ghost is an overlay on Playwright, adding plugins to conceal the differences between a browser used by a human being and a headless browser controlled by a program.
The Playwright-ghost API is identical to that of Playwright, except for the
addition of the plugins option to the
BrowserType.launch([options])
and
BrowserType.launchPersistentContext(userDataDir, [options])
methods.
The plugins property is an array containing the plugins to be added.
Disclaimer
This project is not officially commissioned or supported by Microsoft and Playwright.
Install
playwright-ghost doesn't
provide playwright, so you need to
add it to your dependencies.
npm install playwright playwright-ghostplaywright-ghost can also be used with
patchright or
rebrowser-playwright.
npm install patchright playwright-ghost
npm install rebrowser-playwright playwright-ghostUse
Here's an example with the recommended plugins.
import { chromium } from "playwright-ghost";
// Or to use patchright or rebrowser-playwright:
// import { chromium } from "playwright-ghost/patchright";
// import { chromium } from "playwright-ghost/rebrowser";
import plugins from "playwright-ghost/plugins";
const browser = await chromium.launch({
plugins: plugins.recommended(),
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto("https://example.com/");
const title = await page.locator("h1").textContent();
console.log(title);
await context.close();
await browser.close();In this other example, three plugins are added:
polyfill.headlesshas no options;polyfill.screensets other values for screen size;utils.adblockeruses default options.
import { chromium } from "playwright-ghost";
import plugins from "playwright-ghost/plugins";
const browser = await chromium.launch({
plugins: [
plugins.polyfill.headless(),
plugins.polyfill.screen({ width: 2560, height: 1440 }),
plugins.utils.adblocker(),
],
});
// ...And for this example, the recommended plugins and the utils.locale plugin are
added.
import { chromium } from "playwright-ghost";
import plugins from "playwright-ghost/plugins";
const browser = await chromium.launch({
plugins: [...plugins.recommended(), plugins.utils.locale()],
});
// ...Plugins
⭐️ is in recommended / ⚙️ has options
Polyfill
Humanize
Utils
Debug
Anti-bots
Pass
This 20 anti-bots don't detect Playwright-ghost: Anubis, Brotector, BrowserScan, Chromedriver Detector, Detect CDP, Deviceandbrowserinfo, Device Info Disable-devtool, Fingerprint, Fingerprint Pro Playground, Fingerprint-Scan, HeadlessDetectJS, infosimples, Chrome Headless Detection (Intoli), Check browser fingerprints (iphey), OverpoweredJS Fingerprinting Demo, Pixelscan, Antibot (Sannysoft), Simple Service Workers Fingerprinting Leaks Test and Cloudflare turnstile demo.
To find out which plugins are used, see the anti-bots integration tests.
Fail
This 3 anti-bots detect Playwright-ghost:
- CreepJS: 44% like headless
- rebrowser-bot-detector: mainWorldExecution, pwInitScripts and useragent
- Score detector (reCAPTCHA v3): 0.3
Contributions are welcome to fix these defects.
Customize
You can write your own plugins. A plugin is a function that returns an object containing the hooks. The keys of this object are made up of the class, method and hook type. For example:
"BrowserType.launch:before": modify the input arguments of thelaunch()method of theBrowserTypeclass."BrowserContext.newPage:after": modify the return parameter of thenewPage()method of theBrowserContextclass.
The values of the object are functions applying the modifications.
- For
"before"types, the function receives an array containing the arguments of the hooked method. And it must return a new array containing the modified arguments. - For
"after"types, the function receives the return value of the hooked method. And it must return the modified return value.
/// rickrollPlugin.js
export default function rickrollPlugin() {
return {
"BrowserType.launch:before": (args) => {
return [
{
...args[0],
args: ["--disable-volume-adjust-sound"],
},
];
},
"BrowserContext.newPage:after": (page) => {
page.addInitScript(() => {
// Execute script only in main frame.
if (window !== top) {
return;
}
addEventListener("load", () => {
const iframe = document.createElement("iframe");
iframe.src = "https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ";
document.body.replaceChildren(iframe);
});
});
return page;
},
};
}To use your plugin, add it to the plugins option.
import { chromium } from "playwright-ghost";
import plugins from "playwright-ghost/plugins";
import rickrollPlugin from "./rickrollPlugin.js";
const browser = await chromium.launch({
plugins: [...plugins.recommended(), rickrollPlugin()],
});
// ...This plugin isn't perfect, so let's see how we can improve it (and also discover other features).
