Maximum-stealth browser automation in Python โ plus an MCP server and a script-authoring skill that let your AI agent scrape even highly protected sites. Real Chrome with the default profile, native headful macOS mode, Xvfb on Linux, and rebrowser-playwright CDP-leak fixes.
Pick by the target site. The craft-scraper skill generates a reusable script in whichever fits โ and uses the Ultrastealth MCP to figure out which.
Headed real-Chrome automation with a persistent default-profile runner.
Pure-HTTP, no-browser fetching with TLS impersonation.
__NEXT_DATA__)Detection is fought at the driver, the browser, and the page โ not just with a spoofed user-agent.
Renames rebrowser-playwright's four leaked identifiers (__pwInitScripts, UtilityScript, __playwright_builtins__, __playwright__binding__) at the driver source. Scores 6/6 on rebrowser's bot detector (0 fail; 4 probes correctly skipped as isolated-world-inaccessible by design).
REBROWSER_PATCHES_RUNTIME_FIX_MODE=alwaysIsolated runs page.evaluate off the main world โ 0 positive detections on rebrowser's probe.
Launches real Chrome headfully on macOS and under Xvfb on Linux with a curated flag set โ no headless tells, automation flags stripped, navigator.webdriver:false.
No injected canvas/WebGL/audio spoofing โ benchmarking showed the clean real-Chrome fingerprint already beats a spoofed one on every fingerprint site tested.
The MCP exposes Chrome-DevTools-style capture (browser_network_log/_detail/_response_body) โ perfect for discovering JSON APIs.
Give your coding agent a stealth browser it can drive: navigate, click, type, screenshot, and capture network traffic โ all anti-detection.
# Install ultrastealth + the MCP server, Chromium fallback, and driver patch
curl -fsSL https://raw.githubusercontent.com/anusoft/ultrastealth/main/install.sh | bash
# Re-run the browser install + patch after dependency upgrades
ultrastealth-install
By default Ultrastealth runs chrome+default-profile: real Google Chrome with your OS Chrome user-data root and --profile-directory=Default. On macOS this is native headful Chrome; on Linux headed mode needs an X server โ sudo apt install xvfb and run your agent under xvfb-run -a (or set DISPLAY). If Chrome is already open with the same profile, close it first or set ULTRASTEALTH_RUNNER=chrome+temp-profile / ULTRASTEALTH_USER_DATA_DIR=/path/to/profile. Prefer a repo clone? See the clone install below.
claude mcp add ultrastealth -- ultrastealth-mcp --transport stdio
.mcp.json (project) / ~/.claude/settings.json (global){
"mcpServers": {
"ultrastealth": {
"command": "ultrastealth-mcp",
"args": ["--transport", "stdio"]
}
}
}
Restart, then run /mcp to confirm the ultrastealth tools are listed.
~/.codex/config.toml[mcp_servers.ultrastealth]
command = "ultrastealth-mcp"
args = ["--transport", "stdio"]
codex mcp add ultrastealth -- ultrastealth-mcp --transport stdio
Codex speaks stdio MCP โ keep --transport stdio.
opencode.json (project) or ~/.config/opencode/opencode.json{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"ultrastealth": {
"type": "local",
"command": ["ultrastealth-mcp", "--transport", "stdio"],
"enabled": true
}
}
}
~/.cursor/mcp.json (global) or .cursor/mcp.json (project){
"mcpServers": {
"ultrastealth": {
"command": "ultrastealth-mcp",
"args": ["--transport", "stdio"]
}
}
}
Enable it under Settings โ MCP, then call its tools from chat.
Run the server once and point every tool at a URL instead of spawning a process each:
ultrastealth-mcp --port 8090 # serves http://localhost:8090/mcp
claude mcp add --transport http ultrastealth http://localhost:8090/mcp{ "mcpServers": { "ultrastealth": { "url": "http://localhost:8090/mcp" } } }{ "mcp": { "ultrastealth": { "type": "remote", "url": "http://localhost:8090/mcp", "enabled": true } } }git clone https://github.com/anusoft/ultrastealth.git
cd ultrastealth
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
rebrowser_playwright install chromium
python3 -m ultrastealth.patch_rebrowser
Then use "command": "python3", "args": ["-m","ultrastealth.mcp_server","--transport","stdio"] and set the tool's working directory (or MCP cwd) to the clone.
craft-scraper runs a one-time LLM authoring loop and emits a reusable, deterministic script that reruns forever with no LLM. It uses the MCP to inspect the site, then writes a scrapling-js script (fast, for APIs) or an Ultrastealth script (for protected/JS sites) โ automatically picking the right one.
# the `skills` CLI (vercel-labs/skills) auto-detects your agent and
# installs to the right place โ Claude Code, Codex, Cursor, OpenCode + 70 more
npx skills add anusoft/ultrastealth --skill craft-scraper
Detects installed agents automatically; if it can't, it asks which to use. Run inside a project for project scope, or add -g for global (~/.claude/skills/ etc.). Bun users: bunx skills add โฆ works the same.
npx skills add anusoft/ultrastealth --skill craft-scraper -g -y \
-a claude-code -a codex -a cursor -a opencode
After installing, just ask โ or run /craft-scraper <task + url>. Manage with npx skills list / update / remove.
skills CLI)git clone --depth 1 https://github.com/anusoft/ultrastealth.git /tmp/ultrastealth
mkdir -p ~/.claude/skills # or your agent's skills dir
cp -r /tmp/ultrastealth/skills/craft-scraper ~/.claude/skills/
The skill is plain Markdown (skills/craft-scraper/SKILL.md + reference/), so it also drops in as any tool's native prompt/command/rule.
Ask once. Get a script you can rerun forever.
You โธ /craft-scraper download every product from shop.example.com/catalog
Agent โธ browser_network_enable() # MCP: stealth browser
browser_navigate("โฆ/catalog")
browser_network_log(filter_type="xhr")
โ found JSON API /api/products?page=N โ Path A (speed)
โณ writes scrape_example.js (scrapling-js, no browser at runtime)
bun run scrape_example.js โ 1,284 products across 13 pages โ
# rerun anytime, no LLM:
bun run scrape_example.js --resume
No API and Cloudflare in the way? The agent falls back to Path B and emits an Ultrastealth headed Python script instead โ same skill, same command. For Cloudflare-Turnstile-gated sites it builds in a persistent browser profile + challenge-solving (and notes that those targets need a residential IP). See the worked example examples/egp-announcements.py in the repo.
import asyncio
from ultrastealth import UltrastealthFetcher
async def main():
async with UltrastealthFetcher(headless=False) as us: # macOS headful; Linux uses Xvfb
html = await us.fetch_and_evaluate(
url="https://bot.sannysoft.com/",
js_expression="() => document.documentElement.outerHTML",
wait_secs=3.0,
)
print(html[:500])
asyncio.run(main())