Skip to main content

Dual-mode anti-detect browser framework — CDP-native stealth for local machines, binary-level patching for production servers. No WebDriver, no chromedriver.

Project description

mithwire

A dual-mode anti-detect browser framework for Python.
CDP-native stealth for local machines. Binary-level patching for production servers.
No WebDriver, no Selenium, no chromedriver.

PyPI Python versions License mithwire-mcp


How it works

mithwire is an anti-detect browser automation framework with two stealth modes that cover different deployment scenarios.

CDP mode (default)

The default. mithwire launches a normal Chromium-based browser (Chrome, Brave, Edge) and controls it directly over the Chrome DevTools Protocol. There is no automation driver bolted on the side — the tell-tale signals anti-bot systems use to spot WebDriver/Selenium simply aren't there.

CDP Emulation commands handle timezone, locale, geolocation, user agent, device metrics, and more. This is lightweight, works with any Chromium browser on any OS, and is the right choice when the browser runs on a real desktop where the host machine's fingerprint aligns with the browser profile — no deep lies to maintain.

Best for: local development, macOS/Windows workstations, scripts where the machine's real GPU/fonts/hardware match the presented identity.

Stealth mode (patched binary)

For production Linux/VPS environments where the host machine's fingerprint (SwiftShader GPU, minimal fonts, headless signals) would be trivially detected. Stealth mode swaps in a patched Chromium binary (CloakBrowser) that embeds anti-fingerprinting at the C++ level: canvas, WebGL, AudioContext, fonts, GPU strings, screen dimensions, TLS fingerprint, and CDP detection are all modified in the Chromium source code before compilation.

The browser's JavaScript sees only native values — there are no runtime overrides to detect. mithwire still applies CDP timezone, locale, geolocation, and Accept-Language on top (these complement rather than conflict with the binary's patches).

Best for: headless Linux servers, VPS production workloads, advanced anti-bot targets, situations requiring spoofed fingerprints that can't rely on the host machine's real hardware.

Which mode to use

Scenario Mode Why
Scripting on your Mac/Windows laptop CDP Host hardware is real — no need to lie about GPU, fonts, or canvas
Headless server, no spoofing needed CDP CDP stealth is sufficient when the profile matches the machine
Production VPS scraping/automation Stealth Linux servers expose SwiftShader, minimal fonts, headless signals — the binary patches these at the source
Advanced anti-bot targets (CreepJS, DAB) Stealth Deep fingerprint surfaces (canvas hash, WebGL renderer, audio context) need native-level randomization
AI agent fleet via mithwire-mcp Either CDP for local agents, stealth for cloud/VPS agents — mithwire-mcp supports both via engine parameter

Stealth mode requires the cloakbrowser package and is currently Linux-only for the latest free builds. See mithwire-mcp for the full stealth integration (session management, proxy alignment, profile persistence, and fleet orchestration).


Features

Anti-detect by design — speaks raw CDP: no navigator.webdriver, no chromedriver binary, no Selenium surface to fingerprint

Dual stealth engine — CDP mode for local machines (CDP/JS overrides), stealth mode for production servers (C++ binary-level patches on canvas, WebGL, audio, fonts, GPU, TLS)

Real Chromium browsers — works with Chrome, Chromium, Brave, Edge, and patched CloakBrowser binaries

Headful or headless — visible window or invisible server mode; pairs with Xvfb for headed-on-headless Linux deployments

Identity & fingerprint control — timezone, locale, geolocation, user agent, device metrics, screen dimensions, and more via CDP Emulation

Proxy support — HTTP/HTTPS/SOCKS upstream proxies with automatic authenticating relay for credential-bearing HTTP proxies

Cloudflare Turnstile bypass — one call (tab.verify_cf()) solves the checkbox challenge, light and dark mode

Smart DOM access — find elements by text, CSS selector, or XPath, including inside iframes; lookups double as wait conditions

Full network & event access — the entire CDP surface is available: requests, responses, events, interception

Stateful when you want it — cookies, localStorage, multi-tab & multi-window, screenshots, external-debugger attach

Tiny, async API — up and running in ~2 lines, with best-practice defaults and automatic profile cleanup


mithwire-mcp — give your AI agents a browser fleet

mithwire-mcp

One mithwire browser is great for a script. But what about an AI agent that needs to run dozens of them? That's mithwire-mcp — a Model Context Protocol server that turns mithwire into a tool your LLM can drive directly.

  • Agents launch & control their own browserssession_start, navigate, click, type, screenshot, evaluate — all as MCP tools
  • Fleet management — spin up many isolated sessions at once, each its own browser process, with full lifecycle control
  • Durable identities — persistent profiles with their own cookies, proxies, and fingerprints that survive across runs
  • Consistent stealth at scale — proxy-aligned timezone/locale/geo, fingerprint spoofing, and WebRTC leak protection kept in sync per worker
  • Dual engine supportengine=cdp or engine=stealth per session, mixing modes across a fleet

Get started with mithwire-mcp


Install

pip install mithwire

You'll need a Chromium-based browser (Chrome/Brave/Edge) installed, ideally in the default location. On a headless server, run under Xvfb or use headless mode. To upgrade:

pip install -U mithwire

Quick start

import mithwire as uc

async def main():
    browser = await uc.start()
    page = await browser.get("https://www.nowsecure.nl")
    await page.save_screenshot()

uc.loop().run_until_complete(main())

Use uc.loop().run_until_complete(...) instead of asyncio.run(...) for reliable event-loop handling.

Usage

Custom launch options

from mithwire import start

browser = await start(
    headless=False,
    user_data_dir="/path/to/profile",   # pass one and it won't be auto-cleaned on exit
    browser_executable_path="/path/to/some/other/browser",
    browser_args=["--some-flag=true"],
    lang="en-US",
)
tab = await browser.get("https://example.com")

Or configure via a Config object:

from mithwire import Config

config = Config()
config.headless = False
config.user_data_dir = "/path/to/profile"
config.browser_args = ["--some-flag=true"]

Finding things on the page

# by text — returns the closest match by text length, not the first hit
accept = await tab.find("accept all", best_match=True)
await accept.click()

# by CSS selector (retries until found or <timeout>, so it doubles as a wait)
email = await tab.select("input[type=email]")
imgs = await tab.select_all("a[href] > div > img")

# by XPath
node = await tab.xpath("//button[contains(., 'Next')]", timeout=2.5)

Solving Cloudflare Turnstile

page = await browser.get("https://site-behind-turnstile.example")
await page.verify_cf(max_retries=3, timeout=20, retry_interval=2)

Bundled with light- and dark-mode widget templates and HiDPI-correct coordinates. Requires opencv-python (pip install opencv-python).

Handy tab helpers

Method Does
tab.get_content() current page HTML
tab.save_screenshot() screenshot to a temp file
tab.scroll_down(n) / tab.scroll_up(n) scroll the page
tab.get_local_storage() / tab.set_local_storage(dict) read/write localStorage
tab.add_handler(event, cb) subscribe to CDP events (cb(event) or cb(event, tab))
tab.bypass_insecure_connection_warning() click through invalid-cert warnings
tab.open_external_debugger() inspect a tab without breaking your connection

A fuller, runnable script (automating account creation end to end) lives in the example/ folder.

How it compares

Most "stealth" tools either drive the browser through WebDriver/Selenium (which leaks an obvious automation surface) or patch over it with injected JavaScript (which is itself detectable). mithwire skips both:

  • CDP mode speaks the browser's own debug protocol directly — no driver to fingerprint, no injected shim to catch.
  • Stealth mode goes further with a patched Chromium binary that modifies fingerprint surfaces at the C++ level — canvas hashes, WebGL renderers, audio contexts, and more are natively randomized, invisible to any JavaScript introspection.

No other open-source Python framework combines both approaches under a single API.

Credits & license

mithwire is a maintained fork of nodriver by UltrafunkAmsterdam, itself the successor to undetected-chromedriver. It's distributed under the GNU AGPL-3.0, the same license as upstream. Original copyright and license are preserved in LICENSE.txt; attribution details are in NOTICE. mithwire is not affiliated with or endorsed by the original author.

Stealth mode uses CloakBrowser, a third-party patched Chromium binary (free to use, not redistributable). The cloakbrowser Python wrapper is MIT-licensed. See the CloakBrowser project for binary license details.

This fork addresses real-world limitations hit when running against modern anti-bot systems; fixes land as they're discovered during active use.

Use responsibly. Only automate sites and accounts you're authorized to use, respect Terms of Service and local law, and avoid abusive request rates.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mithwire-0.51.2.tar.gz (416.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mithwire-0.51.2-py3-none-any.whl (438.6 kB view details)

Uploaded Python 3

File details

Details for the file mithwire-0.51.2.tar.gz.

File metadata

  • Download URL: mithwire-0.51.2.tar.gz
  • Upload date:
  • Size: 416.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for mithwire-0.51.2.tar.gz
Algorithm Hash digest
SHA256 e3a67d2897d492b82bafbdd0d343bbff8e8cb331c29bb1ab64474446632ce140
MD5 e85330bc2f1d874df6cad737e13a2b91
BLAKE2b-256 cdad480bfd32377319dee27c3b31f7457bb74eb5d6a646085115cad4c4f514ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for mithwire-0.51.2.tar.gz:

Publisher: release.yml on codeisalifestyle/mithwire

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mithwire-0.51.2-py3-none-any.whl.

File metadata

  • Download URL: mithwire-0.51.2-py3-none-any.whl
  • Upload date:
  • Size: 438.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for mithwire-0.51.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c250581699b724a1ba1278ac087d856f1f16d430a96db6b120beb211bc7eea51
MD5 db26f67162094678f4b9932226a85d9f
BLAKE2b-256 7cf0b828d260d10bee7a15e5f250c14d2214dd930c869715e4cfba9f9f88af62

See more details on using hashes here.

Provenance

The following attestation bundles were made for mithwire-0.51.2-py3-none-any.whl:

Publisher: release.yml on codeisalifestyle/mithwire

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page