首次启动需联网从 GitHub release 下载引擎,代理场景还会下载 GeoIP 数据库;--binary 指定的引擎必须与固定版本一致,否则启动直接拒绝;Web UI 默认监听 127.0.0.1:8765 且无鉴权,改 host 会暴露接口;命令行传 --openrouter-key 会留在 shell 历史和进程列表中,建议改用环境变量或 .env。
invisible_playwright_mcp
feder-crMIT活跃维护基于 Playwright 的 MCP 服务器,让 AI Agent 在反检测隐身 Firefox 上浏览网页,绕过反爬和验证码,适合自动化抓取与求职等场景。
Playwright MCP server undetected by anti-bots and captchas: AI agent browses the web on anti-detect stealth Firefox, Python, undetected browser automation, scraping, computer use.
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
uvx invisible-playwright-mcp ui --openrouter-key sk-or-...README 未说明显存或 GPU 要求;引擎为 Firefox 浏览器二进制,首次启动时从 GitHub release 下载,也可用 --binary 指定已装好的同版本引擎。
基于反检测 Firefox 的 Playwright MCP 浏览器代理,让 AI 助手在反爬和验证码站点上像真人一样操作网页
基于 Playwright 的 MCP 服务器,让 AI Agent 在反检测隐身 Firefox 上浏览网页,绕过反爬和验证码,适合自动化抓取与求职等场景。
核心能力
- 以 MCP 插件形式接入 Claude Code、Codex、Gemini CLI
- 用反检测 stealth Firefox 引擎驱动页面,规避反爬识别
- 提供独立 Web UI,左侧对话右侧实时浏览器画面
- 支持 --proxy 让时区、语言和出口 IP 跟随代理
- 用 --seed 固定浏览器指纹,--profile-dir 保留登录态
容易踩的坑
- v0.73.00.73.0最新正式版2026-10-21 · 2026-10-21 13:51 UTC
0.73.0: the floor rises to invisible-playwright 0.41.0, the first wrapper sealed to firefox-51
- v0.72.30.72.32026-10-17 · 2026-10-17 17:51 UTC
查看更新说明
The floor moves to invisible-playwright 0.37.0 (invisible-core 49.44.0, firefox-49), where the snapshot and every read run in the caller's world.
- A page that replaces getBoundingClientRect keeps its replacement in its own world and no longer reaches the snapshot: the element is measured with the real method and listed. No script can reach the unmeasurable count any more, the caller's included (measured), so its test drives the count through the snapshot's own source with the measuring made to give nothing.
- A navigation that the previous page's own replace stops answers NS_BINDING_ABORTED, an honest answer upstream Playwright gives as well. The tests admit it only with the page then really on /landed, and the snapshot read right after it may meet the previous page still in place only when the navigation was stopped or overtaken.
- The minimise test runs in a visible session: headless=True puts the window on a hidden desktop that EnumWindows does not see, and only a visible window can be minimised by a person. On firefox-49 the capture outlives the minimise, so this arm proves the window is watched again; the restart keeps its clock tests.
- The server builds its engine through one function, process_engine(env), and the one-reader test asks it and plan.engine_here of the same environment.
- v0.72.20.72.22026-10-13 · 2026-10-13 19:26 UTC
查看更新说明
- 0.72.2: the snapshot and read_html read again on the page that replaced the one they went to
invisible-playwright 0.35.2 sends the caller's code once: page.evaluate raises Playwright's navigation error when the page moves under it, because a script waiting on a promise ran twice when it was sent again (B285). The snapshot and read_html are this package's fixed reads without effects, and they reached the page through page.evaluate; they ask page.evaluate_read now, which reads again on the page that replaced the one it went to. browser_evaluate, the model's code, stays on page.evaluate and runs once. The floor moves to invisible-playwright>=0.35.2.
test_read_text_after_a_page_moves_on.py reads each of them first after its own navigation on the seven pages that replace themselves; a unit test says which door each tool takes.
- 0.72.2: the floor moves to invisible-playwright 0.35.4, where a page that replaces itself keeps its main world
On 0.35.2 this PR's e2e failed on /head for the snapshot and read_html: "Page.evaluate_read: the main world never appeared for frame mainframe-9. Worlds seen: ['ctx_aux']". The engine announced only the utility world of the document that replaced the one navigated to, and a read in the page's own world waited 30 s for one that never came (B286). firefox-42, through invisible-core 42.39.0 and invisible-playwright 0.35.4, keeps it. Measured with 0.35.6 (core 44.39.0) under Xvfb 1920x1080: the redirect e2e 29 passed, the floor test 2 passed.
- v0.72.10.72.12026-10-12 · 2026-10-12 12:38 UTC
查看更新说明
The owner's rule of 2026-10-12: a cap only where a real constraint asks for it, never a fixed number out of habit. Three were left that nothing asked for:
- browser_type quoted what the field kept up to 120 characters and then "...". Those sentences exist to say how the field differs from what was typed, and a page that reformats a long value makes the difference anywhere in it.
- A turn that failed said the exception's detail up to 200 characters. The detail is kept because it is the only clue when the cause is real, and a provider's JSON error names the cause past that point.
- The four 503 answers of the panes' routes cut their reason at 200 characters. One function writes that answer now, whole.
Each has a test that turns red when its cap is put back.
- v0.72.00.72.02026-10-12 · 2026-10-12 05:19 UTC
查看更新说明
No answer is cut any more.
browser_read_textstopped at 6000 characters with a line asking for a largermax_chars,browser_evaluateand the browser listing became{"truncated": true, "preview": ...}above the same number, andbrowser_snapshotdropped elements from the end.max_charsis gone from both tools, withDEFAULT_MAX_CHARS,json_cappedandcapped_elements; a caller who wants less narrows the selector. The limitsclean.pyapplies to the HTML stay.browser_read_textright afterbrowser_navigate, on a page that replaces itself, failed with "Failed to find execution context" 9 times in 10: it counted, then evaluated on the first match, and the page moved on between the two. It now finds and reads in one call, with the selector still resolved by the engine.The floor moves to invisible-playwright 0.35.0 (invisible-core 41.36.0): a read caught by a navigation is made again on the page that took its place, and a navigation the previous page's own redirect beats answers at once, naming where the browser went, instead of after the 45 s timeout.
browser_navigate's description says what that answer means.The docs' tool-cost figures are measured again on 0.72.0 with their own published method: 17 tools, 9,207 characters of description, 3,497 tokens of complete definitions, median 189 per tool.
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
Two ways to use this browser agent
1. From your assistant, over MCP
Windows, in PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"
Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
Then install it in your assistant.
Claude Code:
claude plugin marketplace add feder-cr/invisible_playwright_mcp
claude plugin install invisible-playwright-mcp@feder-cr
Codex:
codex plugin marketplace add feder-cr/invisible_playwright_mcp
codex plugin add invisible-playwright-mcp@feder-cr
Gemini CLI:
gemini extensions install https://github.com/feder-cr/invisible_playwright_mcp
2. Standalone: the web UI
We bring the interface, you bring an OpenRouter key. Chat on the left, the live browser on the right.
Windows, in PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"
uvx invisible-playwright-mcp ui --openrouter-key sk-or-...
Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
uvx invisible-playwright-mcp ui --openrouter-key sk-or-...
Then open http://127.0.0.1:8765 and type the same thing.
What to ask a web browsing agent
Anything that needs real web automation: a browser rather than an API, and a person's judgement about what is on the page.
Go to
<paste the URL>. One way, Milan to Lisbon, economy, one checked bag, one adult. Check every date from the 12th to the 16th of next month, one at a time, and read the cheapest fare for each day. The date field is a calendar widget, so click the days rather than typing them. If a date has no availability, say so. Do not guess a number.
It drives the page the way a person would: the pointer moves, keys are pressed.
Options: proxy, profile, seed
--openrouter-keyYour key, or theOPENROUTER_API_KEYvariable.--modelAn OpenRouter model id, orINVISIBLE_MCP_MODEL. Defaults toz-ai/glm-5.3-flash.--proxyOptional.http://user:[email protected]:8080orsocks5://proxy.example.com:1080. Host and port are both required. The timezone, locale and egress follow it.--binaryAn engine binary you already have. It must be the build the seal pins, or startup refuses: this skips the download, not the version check.--seedAn integer. Same seed, same browser identity, every run.--profile-dirA directory to keep the profile in, so logins and cookies survive restarts.--headedShow the browser window. The interface shows you the page anyway.--host,--port127.0.0.1and8765. Changing the host exposes an interface that has no authentication.
A .env beside the command
Rather than retyping the key and the binary path, put them in a .env in the
directory you run from:
OPENROUTER_API_KEY=sk-or-...
STEALTHFOX_BINARY=/path/to/firefox
It is read at startup, and on the way in it never overrides something
already set, so the order is --flag > the environment > .env > the default.
Only the directory you are in is read - there is no search upwards, so running
from a subfolder cannot silently pick up a different key. The startup line names
the variables it applied and never prints their values.
Passing --openrouter-key puts the key in your shell history, and on Linux in
the process list. OPENROUTER_API_KEY in the environment or in a .env avoids
both.
The wiki: AI browser-agent guides
The reading room around the agent lives in the wiki: the AI browser-agent landscape: browser-use, Operator-style and computer-use agents compared, what to check when an agent gets blocked, and what happened to OpenAI Operator, among others. Worked examples, transcripts and their outputs live in articles/.
The rest of the family: engine, core
The MCP server from option 1 ships inside this package: invisible_playwright_mcp with no
subcommand is the server, invisible-playwright-mcp ui the interface. Its config blocks for
clients that take a file, its settings and its tools are on the wiki page
The MCP server.
- invisible_playwright The engine, as a Python library, for writing code instead of prompts. The API is Playwright's.
- invisible_core Seed to fingerprint to preferences, proxy and geolocation.
Using it responsibly
This automates a browser under your control. Read the terms of the sites you point it at, respect their rate limits, and do not submit anything a human has not read.
Privacy Policy
This browser agent runs on your machine and has no server of its own. What leaves your computer, and to whom:
- The sites you visit see the browser, as they would any Firefox.
- Your model provider. The web UI sends the conversation and what the agent reads on the page to OpenRouter under your key. Over MCP, the client you plugged it into does the same with whichever model it uses.
- GitHub. The engine is downloaded from a GitHub release the first time the server or the interface starts, and a GeoIP database is when a proxy is set. Each browser launch also fetches a one-line counter file from a GitHub release, which is how launches are counted: the request carries no identifier and nothing of yours, and GitHub sees what any HTTPS request shows, your IP address.
Nothing else is collected and nothing is sent to the author. Sessions,
profiles and screenshots are stored locally, under INVISIBLE_MCP_HOME if set and
otherwise in the application-data directory of your system, and are yours to
delete; nothing is retained anywhere else. Questions go to the
issues.
License
MIT. Everything distributed before 2 September 2026 was released under AGPL-3.0 and stays under it.