Recommended settings — what to turn on, and what to leave alone
Most blocks we have traced back to a configuration were caused by spoofing more, not less. This page is the short version of what we measured: the settings worth using, the ones that cost you more than they buy, and the handful of problems no setting can fix.
Start here
If you read nothing else on this page, this is the configuration to begin from. It varies the axes that are safe to vary and leaves every surface that can be tested against the host exactly as it is.
import { launch } from "clearcote";
const browser = await launch({
lightStealth: true, // metadata identity only — rendering, TLS and version stay real
fingerprint: "account-42", // ONE stable seed per identity, reused across sessions
proxy: { server: "http://gateway:8080", username: "u", password: "p" },
geoip: true, // timezone + languages + WebRTC egress follow the proxy exit
humanize: true, // trusted native input; navigator.webdriver stays false
});Python is the same surface in snake_case: light_stealth, fingerprint, geoip, humanize. Add axes deliberately, one at a time, and only when you can say what on the host will corroborate them.
The principle: a spoof is a claim the host has to back up
Detection is not a search for unusual values. It is a search for contradictions — two signals that cannot both be true of one machine. An ordinary value nobody spoofed contradicts nothing. A spoofed value with nothing behind it is a positive signal, and it is a stronger one than the value it was hiding.
So the useful question before enabling any option is not “is this value plausible?” but “what on this machine can be asked to corroborate it, and will the answer agree?” Screen dimensions are checked against the render surface. A GPU string is checked against pixels the GPU produces. A claimed operating system is checked against fonts the platform resolves. If the host cannot back the claim, the honest value is the safer one. See How detection works for the mechanics.
Do this
| Setting | Why |
|---|---|
lightStealth: true | Applies a coherent, seed-derived set of the metadata axes only — hardwareConcurrency, deviceMemory, colorDepth, devicePixelRatio, maxTouchPoints — through native single-value switches. Rendering, TLS and the real browser version are untouched, so there is nothing for the host to contradict. |
One stable fingerprint seed per identity | Same seed ⇒ same identity. Reuse it for the life of the account. Rotating the seed per request makes a single logged-in account arrive from a new machine every time, which is a far louder signal than any of the values being rotated. |
geoip: true whenever a proxy is set | Timezone, languages and the WebRTC egress follow the exit IP. A US residential exit reporting Europe/Amsterdam is a one-line check, and it is the single most common self-inflicted mismatch we see. |
humanize: true | Input is generated as trusted native events on real cursor trajectories. Do not layer your own per-step easing on top — set waypoints and let the engine interpolate; hand-rolled easing produces motion statistics that stock input never produces. |
| A persistent context per identity | Cookies, storage and TLS session continuity are part of the identity. A machine that has never seen the site before, every single visit, is its own pattern. |
| Headful under Xvfb in containers | Headed Chrome avoids the headless-mode tells outright. The official image runs this way by default. |
| Run on the OS you intend to claim | The CSS2 system-font keywords are answered by the platform beneath the browser, not by anything the page or the user agent controls, so they survive a user-agent change. Where you cannot, keep the Linux font bundle intact — see below. |
tlsProfile left at match-persona | The ClientHello follows the Chrome version the persona claims, so the network layer and the UA agree. The default is already correct; the reason to know the option exists is to avoid pinning it to something that disagrees with your brand version. |
Avoid these
Each of these is something we measured going wrong, not a general caution.
| Avoid | What goes wrong |
|---|---|
Spoofing screen / avail* on a host whose display does not match | A faked screen size that cannot be reconciled with the real window and render surface is a reliable block trigger on the strictest anti-bots. This is precisely why screen dimensions are not part of lightStealth and are opt-in. If you do set them, set the whole coherent set — screenWidth, screenHeight, availWidth, availHeight — and leave a plausible taskbar gap rather than making avail equal screen. |
| Claiming a GPU on a host that renders in software | On a container, or a cloud VM rasterising through WARP, SwiftShader or llvmpipe, a persona claiming a desktop GPU is describing silicon that cannot produce the pixels the page can read back. From r12, gpuStringSpoof: false reports the host's real WebGL vendor and renderer while leaving everything else alone — often the better trade on that hardware. Note the caveat: WebGPU still follows the wider disableGpuFingerprint, so with the narrow switch alone navigator.gpu keeps describing the persona while WebGL reports the real device. |
Reaching for disableGpuFingerprint or fingerprintNoise: false to change one thing | Both are bundles. disableGpuFingerprint moves the strings and the parameter table and the readPixels farble and persona field suppression; fingerprintNoise: false turns off canvas 2D and WebGL noise together. Since r12 the narrow controls exist: gpuStringSpoof: false for the strings alone and canvasNoise: false for canvas 2D alone. |
| Rotating identity mid-session | Changing the seed, the proxy exit or the timezone while a session is live contradicts the session that came before it. Rotate between identities, never inside one. |
| A Windows persona on Linux with the font bundle stripped out | The Linux release bundles metric-compatible clones (Segoe UI→Selawik, Arial→Arimo, Times New Roman→Tinos, …) and the SDK wires them in via FONTCONFIG_FILE at launch. Strip them, or build a custom image that discards <binDir>/fonts/, and the Windows families the persona claims all collapse onto one default. That is visible without any reference data: two typefaces Windows ships as distinct measure identically. |
| Stacking a JS stealth plugin on top | Clearcote's controls are compiled into the engine. Adding a script-level shim over them reintroduces exactly the self-revealing layer the engine approach exists to remove — an overridden getter stringifies to its own source, and one toString() reads it. |
| A mobile persona on a desktop engine, unqualified | platform: "android" moves the UA, touch points and viewport, but the GPU render and the fine pointer geometry stay desktop. It is a best-effort persona; treat the render surface as the part you still have to solve. |
Proxies
The proxy is usually a bigger determinant of the outcome than any browser flag, and it is the one most often left to a default.
- Sticky exits. One exit IP per identity, held for the session. A session whose IP moves mid-flow contradicts itself regardless of how good the fingerprint is.
- Match the geography to the persona, then let
geoip: truederive the timezone and languages rather than setting them by hand. - Understand the WebRTC trade. Chromium never sends media over an HTTP or SOCKS proxy, so peer traffic would otherwise leave on your real connection where a relay can read your true address. Since r9 media traffic stays on the machine — candidate gathering is unchanged, so the page still sees the shape real Chrome produces, but genuine peer-to-peer UDP will not connect. If you need working peer connections, use a full tunnel (WireGuard/OpenVPN) rather than a proxy, where the traffic has a real path and nothing has to be suppressed.
The part settings cannot fix
Two of the most-read surfaces are decided by the machine you rent, not by the browser you run on it.
| Surface | What the host decides |
|---|---|
| Rendering | A host with no GPU rasterises in software. Every product in this category is reduced to either claiming hardware that cannot render or admitting the software rasteriser. If rendered pixels matter for your target, the fix is a host with a GPU — or the canvas bridge, which forwards the work to one. |
| Fonts | A font list is bounded by what the host can actually draw — as of r12, the canonical list is derived from three thousand real machines and is still intersected with the host, so a page is never told about a font that cannot be rendered. A bare container with four font packages installed therefore reports a small set no matter what the persona claims. Install a realistic font set in the image. |
Check it rather than assume it
Every claim on this page is measurable from inside the browser. Point your configured session at the audit and read the rows it disagrees with — it is the same tooling we used to find the problems described above, and it will tell you which of these recommendations your setup is currently breaking.
Related reading