Skip to main content
Glama
README.md
# firefox-use

**Browser control for Claude Code, on Firefox.**

Claude Code can drive Chrome. This drives Firefox, with the same tools under the same names:
screenshots and clicks, typing and keys, forms, tabs, page reading, console and network logs,
file uploads, and GIF recordings of a whole flow. A browser task written for one browser runs
on the other.

It talks to Firefox over **WebDriver BiDi**, which Firefox speaks natively - no extension, no
geckodriver, and **no npm dependencies**: the WebSocket client, the MCP server, the PNG
decoder and the GIF encoder are all in `src/`, on Node built-ins.

```
you: "log into the staging site and screenshot the dashboard"
     -> read_page finds the form, form_input fills it, computer clicks and screenshots
```

## Install

**As a Claude Code plugin** - the tools and the skill in one step, with the server bundled,
so nothing is downloaded at install time:

```bash
claude plugin marketplace add leetomo2528/firefox-use
claude plugin install firefox-use@firefox-use
```

**From npm**, if you would rather register it yourself:

```bash
npx firefox-use install          # registers the MCP server with Claude Code
npx firefox-use install-skill    # adds the usage skill to ~/.claude/skills
npx firefox-use doctor           # checks Firefox, the profile, the port, the handshake
```

**From source:**

```bash
git clone https://github.com/leetomo2528/firefox-use.git
cd firefox-use && node bin/firefox-use install && node bin/firefox-use install-skill
```

Start a new Claude Code session afterwards. Firefox launches by itself on the first tool call.

Needs **Firefox 129+** and **Node 18+**. Developed and tested on macOS; Linux runs in CI.
Windows is not supported yet.

## The tools

| Tool | What it does |
|---|---|
| `tabs_context_mcp` | The tabs this session can act on. Call it first |
| `tabs_create_mcp` / `tabs_close_mcp` | Open and close tabs of your own |
| `navigate` | Go to a URL, back, or forward |
| `computer` | Click, double/triple/right click, hover, drag, type, keys, scroll, screenshot, zoom, wait |
| `read_page` | Accessibility tree with a `ref_N` on every element |
| `find` | "the search box", "the accept button" - refs by description |
| `form_input` | Set a field by ref: text, number, checkbox, select |
| `get_page_text` | Readable text, markup stripped |
| `read_console_messages` | Console output, filtered by a regex you supply |
| `read_network_requests` | Requests with status, type, timing and size |
| `javascript_tool` | Evaluate an expression in the page |
| `browser_batch` | Several calls in one round trip, stopping at the first error |
| `resize_window` | Resize the window a tab lives in |
| `file_upload` / `upload_image` | Fill a file input; drop a screenshot onto a page |
| `gif_creator` | Record a flow and export an annotated GIF |

Plus three that are ours alone: `firefox_status`, `firefox_restart`, and `firefox_dialog` -
Chrome's integration is finished by a modal dialog, here you can answer it.

## Command line

```bash
firefox-use start [url]      # launch Firefox with BiDi enabled
firefox-use status           # what is running, which profile, which tabs
firefox-use open <url>
firefox-use shot page.png [url] [--full]
firefox-use stop | restart | doctor
firefox-use mcp              # the MCP server on stdio (what Claude Code runs)
```

Options: `--headless`, `--port <n>`, `--profile <dir>`.
Environment: `FIREFOX_BIN`, `FIREFOX_USE_PORT`, `FIREFOX_USE_PROFILE`, `FIREFOX_USE_HEADLESS=1`,
`FIREFOX_USE_DOWNLOADS`, `FIREFOX_USE_UPLOAD_ROOTS`, `FIREFOX_USE_AUTO_RESTART=0`,
`FIREFOX_USE_CALL_TIMEOUT_MS` (the per-call limit, default 150000).

## How it works

```
Claude Code ──stdio JSON-RPC (MCP)──▶ bin/firefox-use mcp
                                        │
                    src/tools.js         registry, shared session, downloads
                    src/pages.js         navigate, tabs, javascript_tool, form_input, resize
                    src/a11y.js          read_page, find, get_page_text
                    src/computer.js      mouse, keyboard, screenshots, zoom
                    src/observers.js     console and network capture
                    src/uploads.js       file_upload, upload_image
                    src/gif.js/gifenc.js recording, PNG decode, GIF89a encode
                    src/batch.js         browser_batch
                                        │
                    src/session.js       tab group, element refs, screenshots, input
                    src/bidi.js          WebDriver BiDi commands and events
                    src/ws.js            RFC 6455 client
                                        ▼
                        firefox --remote-debugging-port 9222
```

Worth knowing:

- **A profile of its own** at `~/.firefox-use/profile`. Log in there once and it sticks; your
  everyday Firefox is never touched. `firefox-use stop` is the off switch.
- **macOS launches through `open -n -a`.** A Firefox started as a child of the shell inherits
  the shell's permissions and dies with *"Could not find profile folder"* under macOS app-data
  protection; `open` hands the launch to launchd instead.
- **A fixed 1280x800 viewport** per tab, at devicePixelRatio 1, so screenshot pixels and click
  coordinates share one coordinate space. `resize_window` changes it deliberately, per tab.
- **Refs are minted per document.** After a navigation, a ref from the old page reports that it
  is gone rather than resolving to whatever now sits at that index.
- **One automation session per browser.** The server closes its session on shutdown;
  `firefox_restart` clears one left behind by a crash.
- **Nothing waits forever.** Every tool call has a deadline (150 s unless
  `FIREFOX_USE_CALL_TIMEOUT_MS` says otherwise), and so does each step beneath it: launching,
  connecting, every BiDi command. A call that runs out of time asks Firefox for a trivial
  answer; if none comes, the connection is dropped and the next call reconnects or relaunches.
- **A Firefox with no window is restarted.** On macOS Firefox keeps running after its last
  window closes, and its `browsingContext.create` then fails with a TypeError whatever it is
  asked for, so no tab can be opened. The next call that needs a tab restarts the browser and
  says it did. Firefox also never closes its own final tab: `tabs_close_mcp` blanks that one to
  `about:blank` and reuses it.

## Development

```bash
npm test                    # unit tests, no browser
npm run test:integration    # + a real headless Firefox, end to end
npm run spec                # generate the parity fixture from your Claude Code install
npm run sync-plugin         # copy the skill into the plugin and stamp versions
```

`npm run spec` writes `.spec/chrome-tool-spec.json` - the Chrome integration's tool
definitions, read out of the Claude Code binary on your own machine. `test/parity.test.js`
compares our schemas against it and `test/prose.test.js` checks that our wording is not
borrowed from it. The file is never committed; those tests skip without it.

## Limits

- The Firefox window is the whole world: no OS-level input, no `about:` privileged pages.
- The accessibility tree covers the top-level document; cross-origin iframes are not walked
  (click by coordinate, or use `javascript_tool`).
- One browser instance per port.

## Notices

MIT licensed. An independent project - not affiliated with Mozilla or Anthropic. Tool names
and parameter shapes match Claude Code's Chrome integration on purpose, so tasks are portable;
the descriptions, the skill and the documentation are written for this project. See
[NOTICE](NOTICE).

TDQS

A4.2/5.0

Scored across 20 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: reading console vs network traffic, page dumps (read_page) vs language search (find) vs prose extraction (get_page_text), and local-file upload (file_upload) vs session-image insert (upload_image) are all cleanly separated by their descriptions. The action tools (computer, form_input, javascript_tool, navigate) target different interaction modes without overlap.

Naming Consistency3/5

Most names follow a verb_noun pattern (read_console_messages, resize_window, file_upload, form_input), but the set mixes in bare single words (navigate, find, computer), a firefox_ prefix (firefox_restart, firefox_dialog, firefox_status), and a _mcp suffix on tabs tools (tabs_create_mcp, tabs_close_mcp, tabs_context_mcp). Still readable but clearly inconsistent conventions.

Tool Count4/5

20 tools is on the heavy side but each earns its place across tab management, page reading, interaction, input, batching and browser control. This is a broad browser-automation surface where the count is justified rather than padded.

Completeness4/5

Covers the core lifecycle well: tab create/close/list, navigation, accessibility-tree and text reading, element finding, JS execution, form filling, file/image upload, console/network inspection, dialogs, resize and restart. Minor gaps like cookie/storage management or a dedicated download handler are workable around via javascript_tool.

Maintenance

ActivityMaintained
ResponsivenessNo issues