Files
daniel156161 34aaf78c66
Testing / test (push) Successful in 28s
Testing / remote-protocol-compat (0.16.0) (push) Successful in 27s
Testing / remote-protocol-compat (0.15.0) (push) Successful in 23s
chore(deps): update python and node dependencies
- Refresh uv.lock with uv sync --upgrade for all resolved Python deps.
- Bump anyio 4.14.2 to 4.15.1 and coverage 7.15.4 to 7.16.0 in the lock.
- Bump pydantic 2.13.4 to 2.13.5 and pydantic-core 2.46.4 to 2.46.5.
- Bump sse-starlette 3.4.8 to 3.4.11 and wcwidth 0.8.2 to 0.8.3.
- Leave direct Python dependency ranges in pyproject.toml untouched.
- Update extension build tooling to esbuild 0.28.2 and typescript 7.0.2.
- Update @types/chrome to 0.2.9 for current MV3 typings.

- Bump n8n-nodes-browser-cli from 0.3.1 to 0.3.2 after the dep refresh.
- Update the node to @noble/post-quantum 0.7.1 and @types/node 26.4.1.
- Pin n8n-workflow dev dependency to 2.37.4 instead of the floating star range.
- The star range resolved to the 2.38.1 beta while npm latest points at 2.16.0.
- 2.37.4 is the current stable dist-tag and audits clean.
- Keep peerDependencies.n8n-workflow as star so host installs stay flexible.
- Switch the node tsconfig to module/moduleResolution Node16.
- TypeScript 7 removed moduleResolution node10, which broke the old build.

- Verified with uv run pytest -q: 639 passed, 98 skipped.
- Verified with npm run check:extension: typecheck, build and 37 tests pass.
- Verified the node with npm ci, npm run build and npm test: 42 tests pass.
- npm audit --audit-level=moderate reports no vulnerabilities in both packages.
2026-09-07 11:05:17 +02:00
..

n8n-nodes-browser-cli

An n8n community node, published on npm as n8n-nodes-browser-cli, that controls a real, visible browser from your workflows via browser-cli.

browser-cli drives a running browser through a native-messaging host and a browser extension — it cannot be installed inside the n8n container. So this node speaks the browser-cli serve protocol directly: a length-framed TCP connection authenticated with an Ed25519 key, with request/response bodies encrypted end-to-end via an ML-KEM-768 (post-quantum) key exchange — the same wire protocol the browser-cli --remote client uses.

n8n workflow ──TCP (Ed25519 + ML-KEM-768)──▶ browser-cli serve (remote host) ──▶ browser

Because the payloads are end-to-end encrypted, the endpoint is safe to expose on an untrusted network without a TLS proxy in front of it.

Remote setup (on the browser machine)

Install browser-cli, register the extension, trust your n8n key, then start serve opening exactly the command tiers you need (it is safe-only by default):

uv tool install real-browser-cli
browser-cli install brave            # one-time: register the extension/native host

# On the n8n side, generate a client key and print its public key:
browser-cli auth keygen -o n8n_key.pem

# On the browser machine, trust that public key (optionally scope its policy):
browser-cli auth trust <pubkey-hex> --allow-control

# Expose the browser. Open only what your workflow needs:
browser-cli serve --host 0.0.0.0 --port 8765 \
  --authorized-keys ~/.browser_cli/authorized_keys --allow-read-page --allow-control

Paste the contents of n8n_key.pem into the n8n credential.

n8n credential — "Browser CLI API"

Field Description
Host host of the serve endpoint, e.g. browser-host.example
Port serve TCP port (default 8765)
Ed25519 Private Key PKCS8 PEM from browser-cli auth keygen (empty only for --no-auth loopback)
Browser Alias optional _route target — required if the endpoint serves multiple browsers
Server Public Key/Fingerprint pinned browser-cli serve identity (SHA256:... fingerprint or 64-char server public key hex)
Allow Unknown Server Identity disables SSH-style server pinning; use only for loopback/dev
Use TLS wrap the connection in TLS (only for a TLS-terminating proxy; the protocol is already encrypted)
Ignore SSL Issues when TLS is on, accept a self-signed proxy cert

Server identity pinning

Recent browser-cli serve versions advertise a persistent Ed25519 server identity in the challenge frame. The n8n node verifies the challenge signature and compares the key against the credential's Server Public Key/Fingerprint field, similar to SSH known_hosts.

On a trusted machine, pin the server once with the Python CLI and copy the fingerprint into the n8n credential:

browser-cli remote trust-host browser-host.example:8765
browser-cli remote known-hosts

If the server key changes, the node fails with REMOTE SERVER IDENTITY CHANGED. Only enable Allow Unknown Server Identity for local/dev endpoints where you explicitly do not want pinning.

Operations

Every operation maps to one raw browser-cli command, each subject to the server policy tier noted below.

Resource Operation Command Server flag needed
Tab List / Query / Get / Count / Filter / Active in Window tabs.list / tabs.query / tabs.status / tabs.count / tabs.filter / tabs.active_in_window safe (default)
Tab Get HTML tabs.html --allow-read-page
Tab Open / Close / Activate / Move / Navigate To / Reload / Hard Reload / Back / Forward navigate.open / tabs.close / tabs.active / tabs.move / navigate.to / navigate.reload / navigate.hard_reload / navigate.back / navigate.forward --allow-control
Tab Mute / Unmute / Pin / Unpin / Dedupe / Sort / Merge Windows tabs.mute / tabs.unmute / tabs.pin / tabs.unpin / tabs.dedupe / tabs.sort / tabs.merge_windows --allow-control
Tab Screenshot tabs.screenshot --allow-dangerous
Page Get Info page.info safe (default)
Page Extract Text / Links / Images / HTML / Markdown / JSON extract.* --allow-read-page
DOM Query / Text / Attribute / Exists dom.query / dom.text / dom.attr / dom.exists --allow-read-page
DOM Click / Type / Select / Hover / Focus / Check / Uncheck / Clear / Submit / Scroll / Key dom.* --allow-control
DOM Eval dom.eval --allow-dangerous
Group List / Query / Tabs group.list / group.query / group.tabs safe (default)
Group Count / Create / Add Tab / Move / Close group.count / group.open / group.add_tab / group.move / group.close --allow-control
Window List windows.list safe (default)
Window Open / Close / Rename windows.open / windows.close / windows.rename --allow-control
Session List / Save / Load / Remove / Export / Diff / Auto Save session.* --allow-control
Storage Get / Set storage.get / storage.set --allow-dangerous
Performance Status perf.status safe (default)
Extension Info / Capabilities extension.info / extension.capabilities safe (default)
Extension Reload extension.reload --allow-control
Client List clients.list safe (default)
Command Execute any command name + JSON args per command

Command → Execute is the escape hatch: any command string the server policy allows (tabs.query, session.save, windows.list, …) with a JSON args object. Use it for anything the typed operations don't cover.

Note: serve returns the raw command result (no SDK post-processing). extract.markdown therefore returns the page payload as the extension hands it back, not the CLI's rendered Markdown. For clean text use Extract Text.

Tab → Filter / Count URL Pattern: matched against the full tab URL. A plain string is a case-sensitive substring (twitch.tv); a pattern containing * or ? is a glob (twitch.tv/*, *.twitch.tv). Glob needs the serve-side extension at 0.16.4+; older extensions treat the whole pattern as a literal substring, so twitch.tv/* matches nothing there — use twitch.tv instead.

Develop / build

cd n8n-nodes-browser-cli
npm install                 # add --ignore-scripts if a transitive native dep
                            # (isolated-vm) fails to compile on your Node version
npm test          # pure unit tests: command mapping + crypto known-answer vectors
npm run build     # tsc -> dist/, copies the icon

Install the published package in n8n as a community node using the package name n8n-nodes-browser-cli, or symlink dist/ into ~/.n8n/custom for local testing.

License

PolyForm Noncommercial License 1.0.0 — same as browser-cli.