# opencode-browser: browser automation for OpenCode over raw CDP

> This OpenCode plugin drives Chrome, Chromium or Electron through direct Chrome DevTools Protocol connections, with no extension and no native host, and it makes the browser endpoint an explicit argument on every tool call.

**different-ai/opencode-browser** — OpenCode plugin to automate Chrome. Inspired by Claude in Chrome.

- Repository: https://github.com/different-ai/opencode-browser
- Stars: 604 · Forks: 53
- Language: TypeScript
- License: not declared
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/different-ai-opencode-browser

## Raw CDP, with no extension and no native messaging host

This package is a browser automation plugin for OpenCode that connects directly to the Chrome DevTools Protocol. The architecture decision is stated up front in the project description. It mirrors the browser tool example from OpenWork, with no Chrome extension, no native messaging host, no local broker and no hidden singleton browser state. Every one of those omissions matters. An extension based approach requires installing something into the browser profile, which you cannot do for a locked down enterprise install, and it usually requires a companion application to bridge the extension to the agent. Talking CDP directly means the plugin is a small client that connects to a debugging port, and it works unchanged against Chrome, Chromium, Electron applications and remote or proxied CDP endpoints. The dependency list explains the shape of the implementation, with the ws WebSocket client as the only runtime dependency and the OpenCode plugin package as a peer dependency.

## browser_url on every call replaces session state

The second architectural choice is that each tool call explicitly receives a browser_url, and the plugin keeps no remembered browser of its own. The project states the reason in three bullets. Direct CDP keeps the package small and predictable, browser_url makes the browser endpoint explicit and portable, and target_id supports multiple tabs and windows without per-session ownership state. In practice that means an agent decides which browser to talk to at each step rather than inheriting one from an earlier turn, which removes a class of surprise where a tool call silently lands in the wrong window. It also makes the plugin usable in parallel, since two calls aimed at two endpoints are just two calls. The cost is verbosity: the endpoint has to be supplied again and again, and the documentation says that if you omit browser_url in CLI calls, OPENCODE_BROWSER_URL is used, then http://127.0.0.1:9222 as the final fallback.

## target_id chooses the tab, and snapshots hand out UIDs

Element selection is handled through an accessibility tree rather than through CSS selectors or coordinates. The browser_snapshot tool returns an accessibility tree snapshot with [uid] markers, and the click and fill tools take a UID from that snapshot. The flow the project documents is a sequence: run browser_list with a browser_url, choose a target_id or omit it to use the first page target, navigate if needed, take a snapshot to get UIDs, then click or fill with a UID from the latest snapshot, and confirm the result with another snapshot or an eval. Two failure modes follow from that design and both are documented. If a click or fill reports that no snapshot is cached, you need to call browser_snapshot first with the same browser_url and target_id, because the UID table is tied to a specific endpoint and target. And when a proxied CDP endpoint returns localhost WebSocket URLs, the plugin rewrites them to the proxy host, which is what makes the proxied case work without manual configuration.

## Seven tools covering navigation, input and inspection

The tool surface is deliberately narrow, and it is worth knowing exactly what you get. browser_list lists page targets on a CDP endpoint, browser_navigate navigates a target to a URL, browser_snapshot returns the accessibility tree with UID markers, browser_click clicks an element by snapshot UID, browser_fill fills an input by snapshot UID, browser_eval evaluates JavaScript in the page, and browser_screenshot captures a PNG screenshot and returns its saved path. Two observations follow from that list. The absence of a wait or idle tool means synchronisation has to come from somewhere else, and the documentation does not describe one, so an agent has to poll with a snapshot or an eval to know when a page has settled. The presence of browser_eval is also a double edged choice, since running JavaScript in the page is the fastest way to read state that the accessibility tree does not expose, and also the fastest way to break a page in a way that only shows up on screen. The screenshot tool returning a path rather than image data keeps large payloads out of the conversation.

## Registering the plugin is a three line configuration

Installing or linking the package and adding it to the OpenCode configuration is the whole setup. The configuration file is opencode.json or opencode.jsonc, and the entry is a plugin array:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["opencode-chrome-devtools"]
}
```

The plugin never starts a browser. The instructions are to start Chrome or Chromium yourself with remote debugging enabled, and on macOS the command is:

```bash
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
```

after which http://127.0.0.1:9222 is the browser_url to use. For Electron applications you pass the app's own exposed CDP endpoint as browser_url, which is the case where an extension based tool would have nothing to work with. The plugin ships a CLI as well, with the binary mapped to bin/cli.js, and the documentation shows it used to list tools and to run one tool directly:

```bash
npx opencode-chrome-devtools tools
npx opencode-chrome-devtools tool browser_snapshot --args '{"browser_url":"http://127.0.0.1:9222"}'
```

The CLI is described as available after a build, and the build script uses bun to bundle the TypeScript source to dist/plugin.js for a node target, with a prepublishOnly hook that builds first.

## A small CLI surface for status and self checks

The package scripts reveal a project that expects to be debugged from the shell. Besides build and publish hooks there are four operational entries: status, which runs node bin/cli.js status, tools, which runs the same binary with the tools argument, self-test, and tool-test, which runs a bun script at bin/tool-test.ts. That pairing is useful in practice, since the failure modes the documentation lists are exactly the kind you diagnose by hand: a browser_list failure means the browser was not started with the remote debugging port or that the /json/list endpoint is not reachable, and a missing snapshot cache means the UID table is empty for that endpoint. Having the same tool invokable from a terminal means the diagnosis does not require reproducing the agent's context. The repository also carries AGENTS.md, GOAL.md and PRD.md at the top level alongside an .opencode directory and an opencode.json, plus three lockfiles, bun.lock, pnpm-lock.yaml and package-lock.json, which is a sign of a tool that has been tried under several package managers.

## MIT in the package, but the version numbers disagree

Two metadata details deserve attention before you depend on this. First, the repository is described as having no classifiable licence while the package.json lists MIT, so the terms you rely on when you install from npm are the ones in that file rather than the ones GitHub would display. Second, the version numbers do not line up. The package.json says version 1.0.0, while the only GitHub release is v4.5.1 dated 2026-01-13, which suggests the npm version field was reset or never advanced alongside the tag sequence. Either way, there is no reliable way to map a published package version to a release tag, so pinning by version alone tells you little about which code you have. The repository is not archived and the last push was on 2026-05-15, so the source has moved since that January release. The package is small, with dist, bin, README.md and .opencode as the published files, and the plugin entry points resolve to dist/plugin.js from both the root export and the ./plugin subpath, so the same build serves the CLI and the OpenCode runtime.

## Conclusion

Adopt opencode-browser if you want an agent to drive a browser you started yourself over CDP, especially against Electron apps where no extension can be installed. Do not expect it to manage a browser for you, since it launches nothing, and check the version mismatch between the 1.0.0 in package.json and the v4.5.1 release tag before pinning a dependency on it.

## FAQ

### How do I set up opencode-browser for OpenCode?

Install or link the package, add "opencode-chrome-devtools" to the plugin array in opencode.json or opencode.jsonc, then start Chrome or Chromium yourself with --remote-debugging-port=9222 and use http://127.0.0.1:9222 as the browser_url.

### Which tools does opencode-browser expose?

Seven: browser_list, browser_navigate, browser_snapshot, browser_click, browser_fill, browser_eval and browser_screenshot. The snapshot returns an accessibility tree with UID markers, and click and fill take a UID from the latest snapshot.

### Why does a click or fill fail with a missing snapshot message?

The UID table is cached per endpoint and target, so you have to call browser_snapshot first with the same browser_url and target_id before a click or fill will resolve an element.

### Can opencode-browser automate an Electron application?

Yes. For Electron apps you pass the application's exposed CDP endpoint as browser_url, which works because the plugin speaks CDP directly instead of relying on a browser extension.

### What licence and version does the opencode-chrome-devtools package use?

The package.json lists the MIT licence, while the repository itself has no licence GitHub can classify. The package.json version field reads 1.0.0 even though the only GitHub release is v4.5.1 from 2026-01-13, so the version numbers should not be trusted to identify a build.

## Sources

- [different-ai/opencode-browser on GitHub](https://github.com/different-ai/opencode-browser)
- [Issues](https://github.com/different-ai/opencode-browser/issues)
- [README](https://github.com/different-ai/opencode-browser/blob/main/README.md)
- [Releases](https://github.com/different-ai/opencode-browser/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/different-ai-opencode-browser
