Skip to content

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 rendering, TLS and the browser version as they are.

javascript
import { launch } from "clearcote";

const browser = await launch({
  lightStealth: true,        // metadata identity only — rendering, TLS and version stay real
  fingerprint: "account-42", // picks this identity's metadata bundle; keep it stable per identity
  proxy: { server: "http://gateway:8080", username: "u", password: "p" },
  geoip: true,               // timezone + languages + the address WebRTC reports 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. Several rows below — the narrow r12 controls, recorded-motion humanize, socks5Udp, the third-party-cookie and proxy switches — apply to the licensed build (Free with GitHub or Pro). The open build ignores them: humanize falls back to generated paths, and a password-protected SOCKS5 proxy refuses the connection.

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

SettingWhy
lightStealth: trueApplies a coherent, seed-derived set of the metadata axes only — hardwareConcurrency, deviceMemory, colorDepth, devicePixelRatio, maxTouchPoints — through native single-value switches. Canvas, WebGL and audio output, TLS and the real browser version are left as they are. The seed only picks which of a small set of bundles an identity gets, and there is no rendering noise, so accounts on one machine share their canvas hash. On a scaled or unusual display, check the pixel ratio the bundle picks against your screen on the audit.
One stable fingerprint seed per identitySame seed ⇒ same identity. Reuse it for the life of the account, on machines with the same graphics maker (see the same seed on different machines). 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. For several accounts on one machine that must not share a canvas, use the seeded persona (drop lightStealth) so each account gets its own rendering noise.
geoip: true on every launchTimezone, languages and the address WebRTC reports follow the exit IP — with or without a proxy (or set timezone and acceptLanguage yourself). Without either, the SDK assumes New York and en-US. A US residential exit reporting Europe/Amsterdam is a one-line check, and it is an easy mismatch to make by accident. If the region can't be resolved, the launch stops with GeoipError instead of starting on this machine's clock — fix the proxy or raise CLEARCOTE_GEOIP_TIMEOUT_SECONDS.
humanize: trueInput is generated as trusted native events on human-shaped cursor paths (recorded human motion for coordinate clicks on Pro, generated paths otherwise). Do not layer your own per-step easing on top — set waypoints and let humanize interpolate; hand-rolled easing produces motion statistics that stock input never produces.
widevine: true under a Chrome brandThe default persona presents as Google Chrome, which answers the Widevine DRM query. Without the CDM the query is refused, which any page can read. See Widevine & DRM.
Leave allowThirdPartyCookies at its defaultThird-party cookies are allowed, as stock Chrome allows them (SDK 0.45.0+), and embedded sign-in, payment and challenge frames rely on them. Set it to false only for a site that should not see them (licensed build, 152 r22+; older builds always block them).
A persistent context per identityCookies, site storage and the cache 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 containersHeaded Chrome avoids the headless-mode tells outright. The official image runs this way by default.
Run on the OS you intend to claimThe 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-personaThe 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.

AvoidWhat goes wrong
Spoofing screen / avail* on a host whose display does not matchA 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. In headless, the SDK already picks a plausible screen for you.
Claiming a GPU on a host that renders in softwareOn 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 licensed build 150 r12 (the open build ignores it), 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 thingBoth are bundles. disableGpuFingerprint moves the strings and the parameter table and persona field suppression (and, on the open build and licensed builds before 154 r34, the readPixels farble); fingerprintNoise: false turns off canvas 2D and WebGL noise together. Since licensed build 150 r12 the narrow controls exist: gpuStringSpoof: false for the strings alone and canvasNoise: false for canvas 2D alone. Both narrow controls have a cost worth knowing: gpuStringSpoof: false moves the WebGL strings but not navigator.gpu, so WebGL and WebGPU end up naming different vendors on the same page — it scores well and reads badly. And canvasNoise: false alongside a seed removes the per-account canvas entirely. Prefer the wide disableGpuFingerprint, which moves WebGL and WebGPU together.
Rotating identity mid-sessionChanging 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 outThe 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.
A Linux persona on a Windows computerWindows runs the GPU through Direct3D, which caps WebGL and WebGPU limits (vertex uniform vectors, the largest texture size, …). A persona can lower a limit but never raise one past what the driver enforces, so a Linux persona on Windows reports limits no real Linux machine has. From SDK 0.41.0 a local launch that claims Linux on a Windows host warns once per process. Claim Windows on Windows, or run Linux personas on Linux or in Docker.
Stacking a JS stealth plugin on topClearcote'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, unqualifiedplatform: "android" moves the UA, touch, pointer type, screen and viewport, but the pixels still come from the desktop GPU (under a mobile GPU name) and fine page geometry stays 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: true derive the timezone and languages rather than setting them by hand.
  • Credentialed proxies go to the engine. HTTP(S) proxy passwords are answered by the browser itself (licensed build 151 r19+; Python & Node SDKs, .NET since 0.58.0), so the page cache stays on and requests aren't marked by interception. SOCKS5 with a password works directly on the licensed build — pass the username and password as separate fields. transparentProxy: true (152 r22+) hides the proxy from request headers and connection timing.
  • 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. The SDK therefore blocks WebRTC UDP that would bypass the proxy. On the open build, geoip / webrtcIp lifts that block; the licensed build keeps it. Pair it with geoip: true (or webrtcIp) so the page still sees the candidates a real Chrome produces, reporting the proxy's address; without it, WebRTC gathers nothing, which reads as blocked. For working peer connections through a SOCKS5 proxy, set socks5Udp: true (licensed build; your provider must allow UDP relaying), or use a full tunnel (WireGuard/OpenVPN) with no browser proxy and pass your own --webrtc-ip-handling-policy in args. Keep the default blocking policy otherwise.

The part settings cannot fix

Some of the most-read surfaces are decided by the machine you rent, not by the browser you run on it.

SurfaceWhat the host decides
RenderingA 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.
FontsA font list is bounded by what the host can actually draw — as of licensed build 150 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. On Linux the SDK uses the font bundle that ships with the browser and ignores fonts installed on the host, so installing packages in your image does not change what pages see, unless you list a directory yourself (SDK 0.41.0+, see your own fonts on Linux). Characters the bundle cannot draw (CJK in the open build; several Indic scripts, Khmer and Ethiopic in licensed builds before r32) show as empty boxes unless fonts for them are listed; the Docker image from sdk-0.41.0 ships them. On Windows the host's own fonts are used. The bundle's Windows look-alikes make widths plausible, but a page can also load a font by name with local(), and a look-alike does not carry the real name: measured with a Windows persona on Linux, Segoe UI and Georgia measured as installed and could not be loaded. Genuine Windows fonts listed with fontDirs render under their own names on the licensed build from r32.
Text scalerEvery glyph is sized by the operating system's font scaler: DirectWrite on Windows, FreeType on Linux. No setting reaches it. Stepping a font size by 0.01 px changes the text width on 99% of steps on Windows and 66% on Linux, and a Linux host presenting Windows still reads 66%. If a page reads your text closely, run on the operating system you claim. See the font stack under the user agent.

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.