Skip to content
SDK · Python · Node · .NET

A stealth browser for Playwright & Puppeteer

Clearcote is Chromium, so the automation you already have keeps working. Swap the launch call for the SDK's launch() and you get back a Playwright handle that drives like a Browser (on a throwaway profile, so newContext() returns that same context), running a build whose identity controls are compiled into the engine instead of injected as JavaScript.

The open build needs no account. The latest build is free with GitHub for one browser at a time.

Change the launch line, keep everything else

# pip install clearcote
from clearcote import launch

browser = launch(fingerprint="account-42", light_stealth=True)
page = browser.new_page()
page.goto("https://example.com")
browser.close()

Highlights

A one-line migration

launch() hands back a Playwright handle on a throwaway profile, so selectors and page objects stay as they are; its newContext() returns that same context, so pass ephemeralProfile: false where you need isolated contexts. Puppeteer attaches to serve()'s CDP endpoint with puppeteer.connect.

A verified binary, fetched for you

On first use the SDK downloads the matching build and checks its SHA-256: the open build against hashes baked into the SDK, the licensed build against the hash its download returns. Opt-in auto-update (open build only) checks the newest release against its published checksums, and their GPG signature when gpg is installed.

Identity as named options

fingerprint, platform, brand, timezone, acceptLanguage, proxy and geoip are arguments, not switches to remember. One seed keeps an identity stable across runs.

Coherent defaults

Headed launches skip the emulated viewport so the page size matches the real window, WebRTC keeps your machine's address private, and QUIC is off behind a proxy so no UDP goes around it.

Humanized input, one flag

humanize: true sends clicks, typing, drags and scrolls as trusted native input on curved paths, with navigator.webdriver left false.

Three languages

Python (sync and async), Node and .NET, on PyPI, npm and NuGet. .NET has geoip too, and humanized input as explicit HumanClickAsync-style calls; saved profiles, render-coherence checks, Widevine and the agent helpers are Python and Node for now.

What the SDK does for you

The package wraps the Clearcote binary so identity options become named arguments. It resolves the browser in a fixed order (an explicit path, the CLEARCOTE_BINARY environment variable, a version you asked for, the latest licensed build when it finds a licence key, then the open build pinned in the SDK), verifies and caches it, launches it through Playwright, and hands back the objects your code already uses.

Because the controls live in the C++ engine, there's no stealth plugin to load and nothing injected into the page. A plugin patches properties from JavaScript, and a patched getter can be told apart from a native one. Here the getter is the native one, in the main frame, in iframes and in workers. How detection works explains why that matters.

Two things behave differently from stock Chromium, both on purpose. Console and page-error events aren't forwarded to the automation client, because forwarding them is what an automation probe measures; collect them in the page and read them back with page.evaluate(). And on the licensed build (free with GitHub), a SOCKS5 proxy with a username and password works directly, with the credentials passed as separate username and password fields, because the engine implements the authentication stock Chromium lacks. The open build can't authenticate to a SOCKS5 proxy.

A stealth plugin next to an engine-level browser

JavaScript stealth plugin
Clearcote
Where the change lives
Script injected into every page and frame
Compiled into the Chromium engine
Native-function checks
A patched getter stringifies to its own source
The getter is native code, so it reports [native code]
Workers and iframes
Each realm has to be patched again, and gaps show
The same values everywhere, from one engine
TLS and HTTP/2
Whatever the underlying browser sends
The engine's own Chrome handshake, matching the version the persona reports
Setup
A plugin, its evasions and their options
One launch() call

Open-source stealth plugins are a reasonable first step, and many projects start there. See the comparison with puppeteer-extra-plugin-stealth for a fuller picture.

What people use it for

Scraping and data collection

Keep your existing Playwright or Puppeteer crawler and change what's underneath it.

End-to-end tests on real pages

Test flows on sites that treat stock automated Chromium differently from a normal browser.

Migrating an existing suite

Selectors and page objects stay put and only the launch call changes. Fixtures that open a fresh context per test need ephemeralProfile: false, because launch()'s newContext() returns its one profile context.

Fingerprinting research

Run the same scripts with and without a persona and compare what a page measures.

Clearcote is built for privacy, testing, research and lawful automation. You're responsible for how you use it and for following the terms of the sites you visit.

Which plan includes it

The SDK is in all three tiers, and so are nearly all identity options (the few that need the licensed build are marked in the fingerprint flags list). Without a key it runs the open build. With a licence key (free with a GitHub account) it runs the latest build, with the licensed-only extras on the pricing page.

Compare plans

FAQ

Is it really a drop-in replacement?

Very nearly. The sync Python and Node launch() hand back a browser-like handle on a throwaway profile: newPage() and everything after it work as before, but newContext() returns that same context, so code that needs isolated contexts should pass ephemeralProfile: false or launch one browser per context. launchPersistentContext() returns a standard BrowserContext. Puppeteer attaches to serve()'s CDP endpoint with puppeteer.connect, and the .NET SDK returns standard Microsoft.Playwright objects (IBrowserContext from LaunchEphemeralProfileAsync, IBrowser from LaunchAsync).

Do I still need puppeteer-extra-plugin-stealth or playwright-stealth?

No, and it's better not to add one. Those plugins patch values from injected JavaScript, and the patching can itself be noticed. Clearcote sets the values in the engine, so there's nothing left for a plugin to patch.

Does it work headless?

Yes. Headed is still the safer default where you can run it, because headless mode has tells of its own. In containers, the official Docker image runs headed under a virtual display by default.

Which languages are supported?

Python (sync and async APIs), Node.js and .NET. All three have geoip matching and humanized input (a launch flag in Python and Node, explicit HumanClickAsync-style calls in .NET). Saved profiles, render-coherence checks, Widevine and the in-browser agent are Python and Node only for now.

How do I keep the same identity between runs?

Reuse the same fingerprint seed, and use launchPersistentContext with a user-data directory so cookies and storage persist. Deriving the seed from your own account or tenant id keeps it reproducible. See persistent identities.

Go deeper in the docs

Related features

Try Clearcote

A drop-in for Playwright & Puppeteer, coherent down to the TLS handshake, with an open-source build to start from.

Free for one browser with GitHub. No card.