Skip to content

Migrating from puppeteer-extra-plugin-stealth

Keep Puppeteer, drop the plugin. Clearcote starts the browser with the fingerprint already set in the engine, and Puppeteer connects to it. Your page code stays the same.

The change

import puppeteer from "puppeteer-extra";
import StealthPlugin from "puppeteer-extra-plugin-stealth";
import puppeteer from "puppeteer-core";
import { serve } from "clearcote";

puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({ args: ["--proxy-server=http://proxy.example:8080"] });
const srv = await serve({
  fingerprint: "acct-1",               // one seed per account: the same device every run
  proxy: { server: "http://proxy.example:8080", username: "user", password: "pass" },
  geoip: true,                         // timezone, language and WebRTC follow the exit IP
});
const browser = await puppeteer.connect({ browserURL: srv.cdpUrl, defaultViewport: null });
const page = await browser.newPage();
await page.authenticate({ username: "user", password: "pass" });
await page.setUserAgent("Mozilla/5.0 ...");
await page.goto("https://example.com");
await browser.close();
await browser.disconnect();
await srv.close();                     // stops the browser and removes its temporary profile

Install with npm install clearcote puppeteer-core. serve() downloads a verified build on first use and starts it with a CDP endpoint on loopback. Keep defaultViewport: null: without it, Puppeteer resizes every page to 800×600, which no longer matches the window the persona gave the browser.

Everything else

With the pluginWith Clearcote
page.emulateTimezone(), --langgeoip: true with a proxy, or timezone and acceptLanguage
page.setViewport()Remove it
evaluateOnNewDocument evasion snippetsRemove them. Patches of navigator or WebGL from a script are what pages look for
userDataDiruserDataDir on serve() (default: a temporary profile, removed on close)
other puppeteer-extra plugins, such as an ad blockerKeep them: puppeteer-extra wraps connect() as it wraps launch(). Only the stealth plugin goes

Or move to Playwright

The SDK's launch() returns a Playwright Browser directly, and adds humanized mouse, keyboard and scrolling (humanize: true), which a client connected over CDP does not get. page.goto, page.evaluate and page.screenshot stay the same; page.$(sel) becomes page.locator(sel), and Playwright waits for elements by itself.

javascript
import { launch } from "clearcote";

const browser = await launch({ fingerprint: "acct-1", humanize: true });
const page = await browser.newPage();
await page.goto("https://example.com");
await page.locator("text=More information").click();   // moves and clicks like a person
await browser.close();

Check the switch

npx clearcote info prints the build the SDK resolves and a launch test. Without a licence key that is the open build (BSD-3, no account); a proxy with a username and password needs the latest build, free with a GitHub sign-in (npx clearcote login). Then open the audit in the old setup and the new one. Comparison: Clearcote vs puppeteer-extra-plugin-stealth.