Part 4 · Browser
Stealth mode: patch nothing that isn't already a tell
Most stealth plugins hide automation by rewriting browser APIs. Modern fingerprinters look for exactly that rewriting. Slapify's stealth mode takes the opposite approach, and on a current Chrome it ends up changing almost no JavaScript at all.
An agent that works on the real web meets bot detection sooner or later. Our Twitter agent ran headless for days, and a headless browser announces itself in several ways: its user agent literally says HeadlessChrome, navigator.webdriver can report true, and a few other properties look nothing like a person's browser. Turning on stealth is one line:
browser:
headless: true
stealth: true
profile: .slapify/browser-profile # a real, persistent profile helps too
or slapify task "…" --stealth for a single run.
Before and after
This is bot.sannysoft.com, a well-known page of automation checks, loaded by the same headless browser twice: once plain, once with stealth. Drag the handle.

Stealth off, four checks fail: the user agent (it says HeadlessChrome/152), navigator.webdriver, and two fingerprint-scanner tests (HEADCHR_UA and CHR_MEMORY). Stealth on: zero failures, and the user agent reads Chrome/152. Captured for this post; you can reproduce it with any Slapify install.
What it actually does
- One launch flag.
--disable-blink-features=AutomationControlledmakes Chromium itself stop reporting automation.navigator.webdriverthen returnsfalsenatively, with nothing in JavaScript to find. - A clean user agent. If the browser advertises
HeadlessChromeand you haven't set one yourself, the browser is relaunched once with the same string minus "Headless". It's done at launch so the HTTP header andnavigator.userAgentalways agree; patching only the JavaScript value would be a tell of its own. - A script that mostly does nothing. A fingerprint script is injected into every frame before page scripts run. Each patch in it checks first whether the value it would fix actually looks automated, and does nothing otherwise.
Why patch so little
Fingerprinters like CreepJS don't just read values. They check whether values have been tampered with: they compare built-in functions against pristine copies pulled from a fresh iframe, inspect stack traces for wrapped getters, walk property descriptors looking for anything that isn't native code, and ask Web Workers (which injected scripts can't reach) for the same values to see if the main thread disagrees.
So every patch is a detection candidate in its own right. A patch that replaces a value that was already realistic buys nothing and adds a lie to be caught in. Hence the rule: patch nothing that isn't already a tell. Try it: set up a browser environment and see which patches would install.
Which patches install?
Tick what's true of the browser. Stealth checks each condition before patching anything.
| Patch | Installed? | Why |
|---|
Two details worth calling out. navigator.permissions.query is deliberately never patched, though most stealth libraries do: the mismatch it used to fix doesn't exist in current Chrome, and wrapping a native method on every page just in case is pure risk. And the Function.prototype.toString cloak, which makes patched getters claim to be native code, is itself detectable. So it's installed only if at least one real patch was, and on a current Chrome that means never.
The numbers
| Test | Stealth off | Stealth on |
|---|---|---|
| bot.sannysoft.com | 4 failures | 0 failures |
| CreepJS headless score | 100% | 33% |
| CreepJS stealth score (detected tampering) | 0% | 0%, same fingerprint hash as an unpatched browser |
| nowsecure.nl (live Cloudflare) | passes | passes |
The 0% stealth score is the point. There is nothing for a tampering detector to find, because on a modern browser stealth mode changes launch flags, not JavaScript.
Where it stops
It is not invisible, and it's worth being precise about why. CreepJS still rates it 33% headless, and what remains is out of reach of anything a page script can do:
- Client hints.
Sec-CH-UArequest headers still identify a headless build. - Workers. Web Worker scopes see the unpatched environment, by design.
- Timing and GPU. Rendering and timing behaviour differ from a desktop browser with a real display.
Closing those gaps means going below JavaScript: patching and rebuilding the engine itself, as projects like invisible_playwright do, or running on real hosted browsers via browser.browserbase. For most sites, a clean fingerprint plus a persistent profile with real history is enough. For the rest, Slapify can drive those browsers too.
Use it responsibly. Stealth is for keeping legitimate automation working, such as your own accounts, your own sites, and research you're authorised to do. Respect sites' terms and rate limits.