Model or dataset
nicobailon/surf-cli avatar
nicobailon/surf-cli

surf-cli: Control Chrome from the Command Line for AI Agents

The CLI for AI agents to control Chrome. Zero config, agent-agnostic, battle-tested.

630 stars60 forksJavaScriptMIT

At a glance

What is it?
surf-cli is a Node.js CLI tool that gives AI agents shell-command access to Chrome through a Unix socket and Chrome's native messaging protocol. It requires no agent-specific configuration, no API keys, and works with any agent framework that can run shell commands.
Who is it for?
surf-cli fits AI agent workflows where the driving process is an LLM or orchestration loop that issues one browser command at a time. It is the wrong tool for cross-browser test suites, Firefox or WebKit automation, or CI pipelines that need a browser to run without a human keeping Chrome open.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Problem surf-cli Solves for Agent-Driven Browsers

Browser automation for AI agents splits into two categories: testing frameworks built around code (Playwright, Puppeteer) and cloud services tied to a specific AI provider. surf-cli targets a third pattern: any process that can execute shell commands and read stdout.

An agent using Claude Code, GPT, Gemini, Cursor, or a plain shell script can type surf go "https://example.com" and get back the page state without writing a test file, setting up an MCP server, or holding an API key. The README describes three design goals: zero config (no MCP server setup, no subscriptions), agent-agnostic operation (the interface is the Unix command line, not a language-specific SDK), and real-world reliability (built by reverse-engineering production browser extensions and testing against pages that resist automation, such as Discord settings panels).

The package is published as surf-cli on npm and the binary is named surf. The repository includes playbooks and skills directories, which contain reusable agent behavior patterns. The README also mentions a WSL2 path: when surf install runs inside WSL2, the tool detects that environment and installs a Windows-side native messaging manifest so that the WSL2 host connects to a Windows Chrome instance, rather than requiring a Linux browser running inside WSLg.

How surf-cli Connects a CLI Command to Chrome

surf-cli uses Chrome's native messaging protocol. An extension, bundled inside the npm package, connects to a native messaging host process (native/cli.cjs) that Chrome spawns on demand. The CLI process communicates with that host over a Unix socket. Three components must be present at runtime: the npm package, the Chrome extension, and the registered native messaging manifest.

Commands follow a flat verb-noun structure. surf go navigates to a URL. surf read returns the page's parsed text content. surf click e5 clicks the element labelled e5 in the last snapshot. surf snap captures a screenshot. Screenshots are automatically resized to 1200 pixels wide before being returned to the calling agent, which cuts token consumption when the agent is feeding images to a vision model. Actions that mutate page state, such as a click or form fill, return a fresh screenshot automatically, saving an extra round-trip.

Installing surf-cli and Running the First Commands

surf-cli is distributed on npm and requires Node.js. Installation has four steps: install the package globally, load the unpacked extension into Chrome, register the native messaging host, then restart Chrome.

Install globally:

bash
npm install -g surf-cli

Find the extension directory:

bash
surf extension-path

Open chrome://extensions, enable Developer mode, click Load unpacked, and paste the path from that command. The extension appears with an ID. Copy it and register the native host:

bash
surf install <extension-id>

Restart Chrome, then verify the connection:

bash
surf tab.list

A successful response lists open tabs. From there, surf go "https://example.com" navigates the active tab, surf read returns parsed content, and surf snap captures a screenshot. The README notes that errors on restricted Chrome pages such as chrome://settings produce warnings rather than hard failures, which prevents an agent loop from crashing on protected URLs.

For Brave, Edge, or Arc, append a --browser flag:

bash
surf install <extension-id> --browser brave

The supported browsers are chrome, chromium, brave, edge, arc, and helium.

Network Capture and AI Queries Without API Keys

Two features address costs that appear in production agent workflows. First, surf-cli logs all network requests automatically while active. The README states this lets users filter, search, and replay API calls without manually configuring request interception. This is useful when an agent needs to observe what a web application sends to its backend, for example to extract a bearer token or confirm that a form submission reached its target endpoint.

Second, surf-cli can query ChatGPT, Gemini, Perplexity, and Grok through the existing browser session rather than through API keys. The README describes this as using "existing browser logins." An agent can send prompts to these models without holding API credentials, as long as an active browser session is present. The README does not document rate limits or output formats for this feature.

Remote Browser Control over Tailscale

surf-cli supports a remote mode where the browser and native host run on one Tailnet machine while the CLI runs on a different machine. The setup requires generating a credential on the host, transferring it to the client through a secure channel, and starting a listener bound to a Tailscale IP.

On the host machine:

bash
surf remote authorize agent-macbook --output ~/agent-macbook.surf-credential.json
surf install <extension-id> --listen 100.101.102.103:4321

From the authorized client:

bash
surf --remote 100.101.102.103:4321 \
  --remote-credential ~/.config/surf/agent-macbook.json \
  tab.list

The README specifies that the listener is available only while the browser extension's native-messaging connection is alive. If Chrome closes or the extension disconnects, remote clients lose access until the extension reconnects. The remote mode uses mutual Ed25519 challenge-response authentication. The README states there is no insecure mode, no downgrade, and no plaintext retry path.

Where surf-cli Is the Wrong Tool

surf-cli works only with Chromium-based browsers. The supported list is Chrome, Chromium, Brave, Edge, Arc, and Helium. Firefox and WebKit are not supported, which rules it out for cross-browser testing or any environment where Chrome cannot run.

The remote listener's availability is tied to the extension's native-messaging connection. If Chrome is closed or the extension is disabled, remote clients lose access until Chrome restarts and the extension reconnects. This means surf-cli cannot drive a browser in a fully headless server environment without additional tooling to keep Chrome running.

The README notes that surf-cli was built partly by reverse-engineering production browser extensions and falls back gracefully when Chrome's DevTools Protocol (CDP) fails. That fallback means some actions on complex pages may produce partial results without a hard error, which can be difficult to detect in an automated pipeline. For package manager installs (Nix, Homebrew), the SURF_NODE_PATH and SURF_HOST_PATH environment variables must be set before running surf install, since the binaries may reside in non-standard locations.

surf-cli vs. Playwright: CLI Commands vs. Test Code

Playwright is the standard alternative for programmatic browser automation. It supports Chromium, Firefox, and WebKit; provides APIs in JavaScript, Python, Java, and .NET; and is designed for test suites where automation logic lives in code files with assertions and a test runner. Playwright gives deterministic, cross-browser control.

surf-cli targets a different pattern: an agent process that issues one command at a time and reads the result. There is no test runner, no assertion library, and no async chain. An agent treats the browser as a terminal subprocess. This works well when the driving process is already an LLM or orchestration loop. It works poorly when the task is a repeatable scripted test that needs deterministic assertions and cross-browser coverage.

The README's comparison table also mentions DevTools MCP as an alternative with no subscription, but it requires MCP configuration rather than a Unix socket CLI, which adds setup steps that surf-cli is designed to eliminate.

Editorial conclusion

surf-cli fits AI agent workflows where the driving process is an LLM or orchestration loop that issues one browser command at a time. It is the wrong tool for cross-browser test suites, Firefox or WebKit automation, or CI pipelines that need a browser to run without a human keeping Chrome open. Before deploying an agent workflow, run surf tab.list after surf install to confirm the native messaging host registered correctly. Each remote client needs its own credential file; never reuse a credential across machines.

Frequently asked questions

How does surf-cli connect to Chrome?

surf-cli uses Chrome's native messaging protocol. A Chrome extension bundled with the npm package connects to a native host process that Chrome spawns on demand, and the CLI sends commands to that host over a Unix socket. The surf install command writes the native messaging manifest to the location Chrome looks up at startup.

Does surf-cli require an API key or a subscription?

No. surf-cli is MIT-licensed and free to use. It supports querying AI services like ChatGPT and Gemini through existing browser sessions rather than API credentials, so no API key is needed for those integrations either.

Which browsers does surf-cli support?

surf-cli supports Chrome, Chromium, Brave, Edge, Arc, and Helium. Firefox and WebKit are not on the supported list. The --browser flag on surf install lets you register the native host for a specific browser or for all supported browsers at once with --browser all.

Official sources

  1. Issues
  2. License: MIT
  3. nicobailon/surf-cli on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nicobailon-surf-cli.svg)](https://hysenlabs.com/projects/nicobailon-surf-cli)