@alessioz/mcp-camoufox
v0.9.3
Published
MCP server for stealth browser automation via Camoufox — 104 tools, Chrome DevTools MCP-level power with anti-bot stealth
Maintainers
Readme
MCP Camoufox
The most feature-rich stealth browser MCP server. 127 tools for full browser control powered by Camoufox — a Firefox fork with C++ level anti-detection that bypasses Cloudflare, bot detection, and anti-automation.
One command. No Python. No manual setup. Everything auto-installs.
claude mcp add camoufox -- npx -y mcp-camoufox@latestWhat Can It Do?
- Login to Google, ChatGPT, GitHub — without getting blocked
- Fill forms, click buttons, type text, upload files
- Manage cookies, localStorage, sessions across visits
- Take screenshots, export PDFs, capture network traffic
- Work with multiple tabs, iframes, dialogs
- Execute JavaScript, inspect elements, scroll pages
- Scrape structured data (job listings, products) with auto-detected selectors
- All while being undetectable by anti-bot systems
Comparison
| MCP Server | Tools | Stealth | npx Install | Persistent Session | |------------|-------|---------|-------------|--------------------| | Chrome DevTools MCP | 30+ | No | Built-in | Yes | | whit3rabbit/camoufox-mcp | 1 | Yes | Yes | No | | redf0x1/camofox-mcp | 45 | Yes | No (clone) | Yes | | Sekinal/camoufox-mcp | 49 | Yes | No (clone) | Yes | | Playwright CLI | 60+ | No | Yes | Yes | | mcp-camoufox | 127 | Yes | Yes | Yes |
Proven on Real Sites
| Site | Challenge | Result |
|------|-----------|--------|
| 2captcha.com/demo/cloudflare-turnstile | Cloudflare Turnstile widget | ✅ "Success!" via click_turnstile() tool (proof) |
| bot.sannysoft.com | Firefox fingerprint tests | ✅ All green (proof) |
| browserscan.net/bot-detection | WebDriver/UA/CDP/Navigator | ✅ All categories "Normal" (proof) |
🎯 Cloudflare Turnstile → Success via click_turnstile()
click_turnstile() auto-detects the widget via 6 selector fallback (iframe[src*=challenges.cloudflare.com], [data-sitekey], .cf-turnstile, …), computes checkbox position (offset_x=30 from widget left), and clicks with a 3-step Bezier-like approach — combined with Camoufox's native humanize + disable_coop for cross-origin iframe click.
Scope: works on Interactive Turnstile (visible iframe widget). Managed Challenge interstitials ("Just a moment...") render the widget in shadow DOM — not supported here; use sister project mcp-stealth-chrome (Chrome+CDP) for those. Real-world bypass success also depends on IP reputation and browser fingerprint — code alone doesn't guarantee it.
🧪 bot.sannysoft.com → Firefox Fingerprint Pass
User Agent reports Firefox/135.0, WebDriver missing, WebDriver Advanced passed, Permissions prompt, Plugins length 5 passed, Languages en-US,en, WebGL Intel HD Graphics — all green. ("Chrome: missing" is expected — Camoufox spoofs Firefox, not Chrome.)
🔍 browserscan.net/bot-detection → All Categories Normal
WebDriver, User-Agent, CDP, Navigator — every detection category returns "Normal". Camoufox's C++-level Firefox patches leave zero automation signals.
Setup
Global (available in all projects):
claude mcp add camoufox --scope user -- npx -y mcp-camoufox@latestProject only (current project):
claude mcp add camoufox -- npx -y mcp-camoufox@latestGlobal — add to config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"camoufox": {
"command": "npx",
"args": ["-y", "mcp-camoufox@latest"]
}
}
}Claude Desktop is always global — no project-level config.
Global — Preferences > Features > MCP, or ~/.cursor/mcp.json:
Project — .cursor/mcp.json in project root:
{
"mcpServers": {
"camoufox": {
"command": "npx",
"args": ["-y", "mcp-camoufox@latest"]
}
}
}Global — ~/.windsurf/mcp.json:
Project — .windsurf/mcp.json in project root:
{
"servers": {
"camoufox": {
"command": "npx",
"args": ["-y", "mcp-camoufox@latest"]
}
}
}Global — VS Code settings or ~/.continue/config.json:
Project — .vscode/mcp.json in project root:
{
"mcpServers": {
"camoufox": {
"command": "npx",
"args": ["-y", "mcp-camoufox@latest"]
}
}
}Global — ~/.factory/mcp.json:
Project — .factory/mcp.json in project root:
{
"mcpServers": {
"camoufox": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-camoufox@latest"],
"disabled": false
}
}
}Or via CLI:
droid mcp add camoufox "npx -y mcp-camoufox@latest"Global — ~/.config/opencode/opencode.json:
Project — opencode.json in project root:
{
"mcp": {
"camoufox": {
"type": "local",
"command": ["npx", "-y", "mcp-camoufox@latest"],
"enabled": true
}
}
}Note: OpenCode uses
"type": "local"(not"stdio") andcommandas a single array.
Global — ~/.trae/mcp.json:
Project — .trae/mcp.json in project root:
{
"mcpServers": [
{
"name": "camoufox",
"command": ["npx", "-y", "mcp-camoufox@latest"]
}
]
}Note: Trae uses an array format for
mcpServers, not an object.
Global — ~/.gemini/antigravity/mcp_config.json:
{
"mcpServers": {
"camoufox": {
"command": "npx",
"args": ["-y", "mcp-camoufox@latest"]
}
}
}Or via UI: Agent Panel > ... > MCP Servers > Manage MCP Servers > View raw config.
Antigravity is global only — no project-level MCP config.
Requirements
| Requirement | Version | Check |
|-------------|---------|-------|
| Node.js | 18+ | node --version |
That's all. Camoufox browser binary (~80MB) downloads automatically on first launch.
All 127 Tools
Browser Lifecycle (4)
| Tool | Description |
|------|-------------|
| browser_launch | Launch stealth browser. Options: url, headless, humanize, geoip, locale, width, height, fresh_profile. If a browser is already running these options are ignored — browser_close first to relaunch. |
| browser_close | Close browser. Reports exactly what survived — e.g. "3 persisted, 1 session-only (dropped)" — so a lost login is never a mystery. Temp profile removed if fresh_profile was used. |
| reset_profile | Wipe the persistent profile at ~/.camoufox-mcp/profile (browser must be closed first) |
| browser_recover | Escape hatch when the browser is wedged and browser_close can't finish: force-drops the connection, resets state, and reports a profile lock held by another Camoufox |
Navigation (4)
| Tool | Description |
|------|-------------|
| navigate | Go to URL. Options: wait_until (domcontentloaded/load/networkidle), timeout |
| go_back | Back in history |
| go_forward | Forward in history |
| reload | Reload page |
DOM & Content (7)
| Tool | Description |
|------|-------------|
| browser_snapshot | Get interactive elements with ref IDs. Call after every navigation. On large pages narrow with roles=["button","textbox"] or paginate with offset/limit — refs stay stable. |
| screenshot | Capture viewport, full page, or one element (ref / selector — perfect for documenting a modal). Returns the image inline plus the saved path, so no second read step. return_image=false for path only. |
| get_text | Text from page or selector (max 5000 chars) |
| get_html | HTML from page or selector (max 10000 chars) |
| get_url | Current URL + title |
| save_pdf | ⚠️ Not available on Camoufox — Playwright implements PDF generation only for headless Chromium, and Camoufox is Firefox. Returns a clear error; use screenshot(full_page=true) instead. |
| search_page | Grep the current page's visible text with surrounding context — costs nothing next to a snapshot or screenshot |
Element Interaction (12)
| Tool | Description |
|------|-------------|
| click | Click by ref ID. Options: button, dblclick. If the real mouse click is blocked, it falls back to a full synthetic pointer sequence (pointerdown→mousedown→pointerup→mouseup→click) and says so — a degraded click is never reported as a clean one. |
| click_text | Click by visible text. Refuses to guess: several matches → fails with a numbered candidate list (tag, text, ancestor path, ref). Narrow with within ("@dialog", a CSS selector, or "ref:e5") or choose with index. |
| click_role | Click by ARIA role + name. Same within / index / ambiguity guard as click_text. |
| hover | Hover over element |
| fill | Fill input/textarea — always replaces the old value (email/number inputs are cleared explicitly first; Firefox's select-all is a no-op on those, which otherwise made a re-fill append) |
| select_option | Select from dropdown |
| check / uncheck | Toggle checkbox/radio |
| upload_file | Upload file to input |
| click_element_offset | Click at an x%/y% position inside an element — wide labels whose real checkbox sits at the left edge, sliders, split buttons |
| click_at_corner | Click a corner (close/X, delete, dismiss controls live there, not in the centre) |
| paste_text | Fill via a real clipboard paste (Ctrl/Cmd+V) so frameworks that only listen for paste — Svelte 5 / Solid runes, some Qwik forms — actually receive it |
Keyboard (2)
| Tool | Description |
|------|-------------|
| type_text | Type char by char. Options: delay. For OTP, masked inputs, date pickers. |
| press_key | Key or combo: Enter, Escape, Tab, Control+a, Meta+c |
Mouse XY (4)
| Tool | Description |
|------|-------------|
| mouse_click_xy | Click at exact coordinates. Optional steps (0=instant, 15-30=human-like pre-movement) |
| mouse_move | Move cursor to coordinates. Optional steps for interpolated path |
| click_turnstile | Auto-find + humanized click on Cloudflare Turnstile widget. Params: offset_x (default 30), offset_y, wait_render_ms. Works on Interactive Turnstile (visible iframe widget). Not for Managed Challenge interstitials. |
| drag_and_drop | Drag between two elements |
Wait (7)
| Tool | Description |
|------|-------------|
| wait_for | Wait for selector or text (visible/hidden/attached/detached) |
| wait_for_navigation | Wait for page load |
| wait_for_url | Wait for URL pattern match. Wrap in /…/ for regex; a bare /path is treated as a substring. |
| wait_for_response | Wait for network response pattern |
| wait_for_change | Wait until the page actually CHANGES and report what changed (url/title/DOM size/text) — the honest replacement for a fixed sleep after a click |
| wait_for_request | Block until the page ISSUES a matching request — confirms an action really fired its API call |
| wait_for_any_of | Race several conditions (selector/text/url_contains/title_contains) — returns the first that matches so the agent can branch in one call. Ideal for post-login flows. |
Tabs (4)
| Tool | Description |
|------|-------------|
| tab_list | List all tabs. Pages the site opens itself (window.open / target=_blank, e.g. OAuth popups) are auto-tracked and appear here too. |
| tab_new | Open new tab |
| tab_select | Switch tab by index or url_contains (first tab whose URL matches) |
| tab_close | Close tab by index (-1 = active) or url_contains. The active tab is tracked by identity, so closing a lower-indexed tab never silently switches you to another one. |
Cookies (3)
| Tool | Description |
|------|-------------|
| cookie_list | List cookies. Options: domain filter |
| cookie_set | Set cookie with expires_days, http_only, secure, same_site. expires_days=0 (default) makes a session cookie that dies at browser_close — pass a lifetime to keep a login across relaunches. |
| cookie_delete | Delete by name/domain. Empty = clear all. |
Local Storage (3)
| Tool | Description |
|------|-------------|
| localstorage_get | Get all or specific key |
| localstorage_set | Set key-value |
| localstorage_clear | Clear all |
Session Storage (3)
| Tool | Description |
|------|-------------|
| sessionstorage_get | Get all or specific key |
| sessionstorage_set | Set key-value |
| sessionstorage_clear | Clear all sessionStorage for the origin (parity with localstorage_clear) |
JavaScript (2)
| Tool | Description |
|------|-------------|
| evaluate | Run JS in page context |
| inject_init_script | Inject script that runs on every page load |
Element Inspection (5)
| Tool | Description |
|------|-------------|
| inspect_element | Full element info: tag, attributes, box, styles |
| get_attribute | Get specific attribute |
| query_selector_all | Query multiple elements by CSS selector |
| get_links | Get all links with URL + text. Options: filter |
| form_introspect | Whole-form analysis in one call: label, type, value, required/pattern/length, validation state, and the JS framework each field is bound to |
Frames (2)
| Tool | Description |
|------|-------------|
| list_frames | List all frames/iframes |
| frame_evaluate | Run JS inside a frame |
Batch Operations (6)
| Tool | Description |
|------|-------------|
| batch_actions | Multiple actions in one call (click, fill, type, press, wait) |
| fill_form | Fill multiple fields + optional submit |
| login_classic | Composite login for email→password forms (Google/Microsoft/generic). Auto email→Next→password→submit, optional TOTP 2FA (totp_secret or totp_code). Collapses 5–8 calls into one. |
| navigate_and_snapshot | Navigate + snapshot in one call |
| smart_fill | Fill fields by label text (fuzzy) instead of refs — no snapshot needed; optional submit_label |
| workflow_run | Run a list of tool calls in sequence; resumable via start_at after a failure |
Viewport (2)
| Tool | Description |
|------|-------------|
| get_viewport_size | Get width x height |
| set_viewport_size | Set dimensions |
Scroll (2)
| Tool | Description |
|------|-------------|
| scroll | Scroll up/down/left/right by pixel amount |
| scroll_to | Scroll a specific element into view (ref/selector, block alignment) |
Dialog (2)
| Tool | Description |
|------|-------------|
| dialog_handle | Pre-set accept/dismiss for the next alert/confirm/prompt on any open tab (first dialog wins, then disarms) |
| dialog_auto_handle | PERSISTENT handler — stays armed across every dialog and every tab, including popups. enabled=false removes it |
Accessibility (1)
| Tool | Description |
|------|-------------|
| accessibility_snapshot | Accessibility tree for LLM understanding |
Console & Network (5)
| Tool | Description |
|------|-------------|
| console_start / console_get | Capture and retrieve browser console messages. Capture spans all tabs and follows newly opened tabs/popups (re-calling console_start resets cleanly — no listener stacking). |
| network_start / network_get | Capture network requests across all tabs (follows tab switches + popups). network_start(capture_bodies=true) also records request/response headers + text bodies. network_get(filter=...) narrows by URL substring; each row shows an #id. |
| network_get_detail | Full request + response (headers + text body) for one captured request by #id or url substring. Needs capture_bodies=true. Replaces the evaluate()+fetch() workaround for inspecting API payloads. |
Compound (reduce round-trips) (4)
| Tool | Description |
|------|-------------|
| wait_and_snapshot | Wait for selector/text + return snapshot in one call |
| back_and_snapshot | Navigate back + return snapshot |
| reload_and_snapshot | Reload page + return snapshot |
| click_and_snapshot | Click + wait + return snapshot. Perfect for buttons that trigger navigation. |
Smart Selectors (skip snapshot) (3)
| Tool | Description |
|------|-------------|
| find_by_text | Find by visible text — returns every match with a ref, ancestor path and total, so you can see whether the one you'd click is the one you mean. Supports within. |
| find_by_label | Find input by label text, returns ref (lists all candidates if several match). Supports within. |
| find_by_placeholder | Find input by placeholder, returns ref (lists all candidates if several match). Supports within. |
Session Portability (7)
| Tool | Description |
|------|-------------|
| cookie_export | Export all cookies as JSON (for transfer) |
| cookie_import | Import cookies from JSON (restore session) |
| cookie_export_file | Write all cookies to a JSON file (Playwright format) |
| cookie_import_file | Load cookies from a JSON file (Playwright format) |
| storage_state_save | Save cookies + localStorage + sessionStorage to JSON file. Reload to skip login/CF. |
| storage_state_load | Restore session from JSON (cookies + storage). Use navigate_to param to apply localStorage. |
| auth_capture | Convenience: save current session to ~/.camoufox-mcp/sessions/<name>.json |
Humanize / Anti-Bot (5)
| Tool | Description |
|------|-------------|
| humanize_click | 3-step Bezier mouse approach + small jitter before click. Scrolls the target into view first (a real mouse click can't reach an off-screen element). Use for CF/DataDome pages. |
| humanize_type | Gaussian-distributed keystroke delays (mean 80ms, sigma 30ms). Mimics human rhythm. |
| mouse_drift | Random mouse movements over duration — builds mouse history before action. |
| mouse_record / mouse_replay | Capture human mouse path then replay (anti-bot gold). |
Session Warmup & Detection (2)
| Tool | Description |
|------|-------------|
| session_warmup | Visit Google/Wikipedia (random) before targeting protected site. Helps IP scoring. |
| detect_anti_bot | Heuristic detection of CF/DataDome/Akamai/PerimeterX/Imperva/reCAPTCHA/hCaptcha. |
Assertions (4)
| Tool | Description |
|------|-------------|
| assert_element_visible | PASS/FAIL — element exists and is visible |
| assert_text_present | PASS/FAIL — text substring on page |
| assert_url_matches | PASS/FAIL — URL matches pattern (substring or regex) |
| assert_clickable | Hit-test without clicking: would a real click land? Names the element that would intercept it |
Workflow Helpers (3)
| Tool | Description |
|------|-------------|
| click_and_wait | Click + wait for navigation/selector atomically (fewer roundtrips) |
| wait_for_network_idle | Wait until there are zero in-flight requests for idle_ms continuously (tracked per request — the threshold really is yours, not Playwright's fixed 500 ms) |
| describe_page | Compact LLM-friendly summary (title, h1, buttons, links, forms) + intent classifier (login_email, otp_input, captcha, stay_signed_in, …) — cheaper than browser_snapshot |
Scraping & Extraction (4)
| Tool | Description |
|------|-------------|
| detect_content_pattern | Auto-detect repeated content (cards, listings) and suggest CSS selectors. Run this before extract_structured. |
| extract_structured | Extract data from repeated elements as clean JSON. Auto-deduplicates, filters empties, direct_text_only prevents field mixing. |
| extract_table | Extract HTML table as JSON array with auto-detected headers |
| scrape_page | Smart scraper: auto-extract main content (strips nav/footer), links, meta, headings. Smart truncation at paragraph boundary. |
Browserless HTTP (4)
The browser is the expensive path. impit (already shipped with camoufox-js) speaks a real Firefox TLS/HTTP2 fingerprint, so these tools fetch without launching anything — and the fingerprint matches the browser this server actually drives. Verified against a Cloudflare-protected site that these tools cleared without opening a browser at all.
No
web_search/deep_researchhere by design: scraping a SERP without an API key returns confidently wrong results for whole classes of query (Bing answers any "how does …" question with dictionary pages) and one major engine is TLS-blocked by some ISPs. A search tool that fails silently is worse than none — use your client's own search (WebSearch/Exa/Tavily) and feed the URLs toscrape_markdown.
| Tool | Description |
|------|-------------|
| http_request | HTTP with a real Firefox TLS fingerprint, reusing the live browser's cookies by default — log in with the browser, then hit the site's API cheaply |
| http_session_cookies | Show which browser cookies would be sent to a URL (verify session sharing before relying on it) |
| scrape_markdown | One URL → clean LLM-ready markdown (headings/links/lists kept, nav/footer/scripts stripped). Browserless by default, use_browser=true for JS-heavy pages |
| smart_fetch | Tries HTTP first, escalates to the stealth browser only when the response looks anti-bot blocked. The efficiency core |
Storage Inspection (4)
| Tool | Description |
|------|-------------|
| storage_snapshot | Capture cookies + localStorage + sessionStorage into a named slot |
| storage_diff | Diff current state against that slot — the fastest way to find which key holds a session token |
| indexeddb_list | List IndexedDB databases for the origin (where many SPAs hide auth state) |
| indexeddb_delete | Delete an IndexedDB database by name |
Debug (5)
| Tool | Description |
|------|-------------|
| server_status | Health check: browser status, tabs, URL |
| get_page_errors | Uncaught JS errors + unhandled promise rejections, captured by a hook installed at browser_launch. Buffer resets on every navigation — read it before navigating away. |
| export_har | Export captured traffic as a valid HAR 1.2 file (opens in DevTools). Needs network_start first; headers/bodies included only with capture_bodies=true. |
| page_stats | Element count, page size, load metrics + extraction strategy recommendation |
| performance_timeline | TTFB, DOMContentLoaded, load, FCP, LCP + the 5 slowest resources (CLS is unavailable — Firefox has no layout-shift API) |
Site Automation (2)
| Tool | Description |
|------|-------------|
| chatgpt_generate_image | End-to-end image generation/edit on chatgpt.com in one call: fresh chat → optional reference-image upload → prompt → wait for the finished image → save PNG to output_path. Requires an authenticated chatgpt.com session. |
| chatgpt_generate_batch | Many images in parallel (one tab per job, submit-all-then-collect). shared_image_paths + style_suffix keep a set visually consistent. |
Examples
Login to a website
browser_launch(url="https://accounts.google.com", headless=false)
browser_snapshot() # see email input
fill(ref="e1", value="[email protected]") # fill email
click(ref="e4") # click Next
wait_for(selector='input[type="password"]') # wait for password page
browser_snapshot()
fill(ref="e2", value="mypassword") # fill password
click(ref="e4") # click NextFill a form in one call
fill_form(
fields=[
{ref: "e3", value: "John Doe"},
{ref: "e5", value: "[email protected]"},
{ref: "e7", value: "Hello world"}
],
submit_ref="e10"
)Batch multiple actions
batch_actions(actions=[
{type: "click", ref: "e5"},
{type: "wait", timeout: 1000},
{type: "fill", ref: "e8", value: "search query"},
{type: "press", key: "Enter"}
])Search Google
browser_launch(url="https://google.com")
browser_snapshot()
click(ref="e5") # search box
type_text(text="mcp-camoufox npm")
press_key(key="Enter")Multi-tab research
browser_launch(url="https://github.com")
tab_new(url="https://stackoverflow.com")
tab_list()
tab_select(index=0)Wait for API response
click(ref="e10")
wait_for_response(url_pattern="/api/data")
browser_snapshot()Inspect elements
inspect_element(ref="e5")
get_links(filter="github.com")
query_selector_all(selector=".product-card")Work with iframes
list_frames()
frame_evaluate(frame_index=1, expression="document.title")Scrape job listings (structured)
browser_launch(url="https://glints.com/id/opportunities/jobs/explore")
detect_content_pattern() # auto-suggest selectors
extract_structured(
container_selector=".job-card", # from detect_content_pattern
fields=[
{name: "title", selector: "h3"},
{name: "company", selector: ".company-name"},
{name: "location", selector: ".location"},
{name: "url", selector: "a", attribute: "href"}
]
)Scrape page content (smart)
scrape_page(only_main_content=true, max_text_length=8000)
# Returns: title, url, meta, text (truncated at paragraph boundary),
# links, headings, truncated flag, total_text_lengthManage storage
localstorage_get()
localstorage_set(key="token", value="abc123")
cookie_list(domain="example.com")How It Works
AI Agent (Claude, Cursor, Windsurf, VS Code)
|
| MCP Protocol (stdio JSON-RPC)
v
mcp-camoufox (Node.js)
|
| Playwright API (Juggler protocol, NOT CDP)
v
Camoufox (Patched Firefox binary)
|
| C++ anti-fingerprint patches
v
Website (Cloudflare, bot detection — bypassed)Why stealth works
- Juggler protocol instead of CDP — sites detecting Chrome DevTools Protocol cannot detect Camoufox
- C++ level patches — fingerprint spoofing at browser engine level, not JavaScript injection
- GeoIP auto-detection — timezone, locale, geolocation match your real IP
- Human-like behavior — optional
humanizemode for realistic mouse movements
Why sessions persist
Browser profile stored at ~/.camoufox-mcp/profile/. Cookies, localStorage, IndexedDB survive across sessions. Login once, stay logged in.
Why refs work better
browser_snapshot tags elements with data-mcp-ref attributes. This is:
- More token-efficient than sending full HTML
- More reliable than CSS selectors that break when sites update
- Clickable via
click(ref="e5")— no selector gymnastics
Data Storage
| Path | Contents |
|------|----------|
| ~/.camoufox-mcp/profile/ | Browser profile (cookies, localStorage, cache) |
| ~/.camoufox-mcp/screenshots/ | Screenshots, PDFs, HAR exports |
Reset everything: rm -rf ~/.camoufox-mcp/ — or call the reset_profile tool (browser must be closed first).
Switching between accounts on the same domain
The default profile persists across browser_close calls, so the next login on the same domain inherits cookies + session — sometimes redirecting to the wrong account. Two options:
browser_launch(fresh_profile=true)— uses a temp profile dir that's removed onbrowser_close. Best for one-off logins.reset_profile(browser must be closed) — wipes the shared profile entirely.
Troubleshooting
| Problem | Fix |
|---------|-----|
| "Browser not running" | Call browser_launch first |
| Click blocked by overlay | A synthetic pointer-event fallback fires and the response warns you (⚠). If the widget still ignores it, dismiss the blocker (press_key("Escape")) or use mouse_click_xy. |
| Clicked the wrong "Cancel"/"Save" | click_text now fails with a candidate list instead of guessing. Use within="@dialog" to stay inside the open modal, or index=N. |
| Click on a Radix/Headless UI/MUI option did nothing | The real click was blocked and the old fallback used a bare el.click(), which those libraries ignore. Fixed — the fallback now replays the full pointer sequence. Upgrade if you're on ≤0.7.2. |
| Login gone after browser_close | cookie_set without expires_days creates a session cookie, which no browser writes to disk. Pass expires_days=30, or use storage_state_save/auth_capture. browser_close now tells you how many cookies were dropped. |
| Stale refs after navigation | Call browser_snapshot again — refs regenerate each time |
| Window too large | browser_launch(width=1024, height=768) |
| First launch slow | Downloading Camoufox binary (~80MB). Happens once. |
| Huge snapshot output | Normal for big pages. Use get_text or evaluate instead. |
| iframe not accessible | Use list_frames + frame_evaluate |
| CAPTCHA appears | Cannot auto-solve. Use headless=false and solve manually. |
| Login lands on wrong account | Profile carry-over. Use fresh_profile=true on launch or reset_profile. |
| Need a PDF | save_pdf can't work on Firefox/Camoufox. Use screenshot(full_page=true). |
| Field value looks concatenated | Fixed — fill/fill_form/batch_actions/login_classic now clear email/number inputs before typing. Upgrade if you're on ≤0.7.2. |
| humanize_click did nothing | Fixed — it now scrolls the element into view and errors if the element is outside the viewport. |
| MCP server silently dies | If you ran pkill -f camoufox, you killed the MCP node process too (its argv contains "camoufox"). Target the binary specifically — e.g. pkill -f "Camoufox.app/Contents/MacOS" — or use pkill -f camoufox-js. |
License
MIT
Built by RobithYusuf
