---
summary: "Chrome extension: securely automate signed-in tabs with automatic local pairing"
read_when:
  - You want an agent to drive your signed-in Chrome without remote-debugging prompts
  - You are installing, pairing, disabling, or troubleshooting the OpenClaw Chrome extension
  - You need the Chrome native bootstrap security and platform support model
title: "Chrome Extension"
---

# Chrome extension

The OpenClaw Chrome extension lets the browser tool automate eligible tabs in
your signed-in Chrome profile. It uses `chrome.debugger`, so it does not require
Chrome's blocking remote-debugging consent prompt.

The extension is browser automation infrastructure. It does not include chat,
page sharing, a prompt box, or a tab copilot. Its popup shows connection state,
the current access mode, a Pause/Allow action for the current eligible tab, and
a Settings link.

## Requirements

- Google Chrome, Chrome for Testing, or Chromium
- OpenClaw installed on the same machine as Chrome, or an OpenClaw browser node
  on that machine
- macOS or Linux for automatic native bootstrap
- Chrome launched at least once so its user-data directory exists

Windows keeps manual pairing. Current Chromium launches native hosts directly
only when the registered host is a Windows executable; OpenClaw does not install
a script launcher or registry key without a proven binary framing path.

## Install

Launch Chrome, then run this command before loading the extension:

```bash
openclaw browser extension install
```

Keep the command running. It copies the bundled extension to a stable
OpenClaw-owned directory, predicts the unpacked extension ID from that exact
path, and pre-registers an origin-locked native host in existing Chrome-family
user-data roots. Only after pre-registration succeeds does it print the stable
path to load.

Chrome does not let a normal CLI silently install an unpacked extension. This
one step is unavoidable:

1. Open `chrome://extensions`.
2. Enable **Developer mode**.
3. Click **Load unpacked**.
4. Select the path printed by the command.

Leave the install command running while you complete those steps. The extension
pairs on its first native call; you do not need to open its popup, reload the
extension, or restart Chrome during a normal first-time setup. The installer
then reads the profile's `Secure Preferences` and verifies that Chrome loaded
the approved realpath under the predicted ID.

The installer accepts an ID only when all of these are true:

- the ID matches Chrome's 32-character extension ID format;
- Chrome records the install location as unpacked;
- the recorded extension path resolves exactly to the installed or bundled
  OpenClaw extension directory;
- the recorded ID equals Chromium's deterministic path ID for that exact
  canonical realpath.

The extension name is not trusted. Existing native-host files with the same
host name are not overwritten unless they are verifiably OpenClaw-owned.

Use a different bounded wait when needed:

```bash
openclaw browser extension install --wait-ms 60000
```

For automation, use `--json`. The result includes the stable copy, discovered
IDs and profiles, native-host registration health, and whether manual setup is
required. It never includes a relay key or pairing string.

## Use it

Select the built-in `chrome` profile, or make it the default:

```bash
openclaw config set browser.defaultProfile chrome
```

```json5
{
  browser: {
    profiles: {
      chrome: { driver: "extension" },
    },
  },
}
```

Fresh automatic pairings use **All tabs**. Existing valid pairings are never
overwritten, and older pairings keep their stored access mode.

For local setup, native bootstrap connects the extension through the local
Gateway's exact `/browser/extension` route. That first authenticated connection
wakes the lazy browser-control service and starts the profile's loopback relay;
OpenClaw and local clients such as mcporter then use that profile relay port.
Keep `openclaw gateway run` or the managed Gateway service running. A separate
browser request or prewarm step is not required.

Browser-node setup remains different: the extension connects to the relay on
the browser-node host while the node uses its configured remote Gateway. An
explicit `--gateway-url` pairing connects directly to that remote Gateway and
remains a manual-only flow.

### Choose tab access

- **All tabs** exposes every eligible ordinary tab in that Chrome profile,
  except tabs paused for the current browser session. Use **Pause on this tab**
  and **Allow on this tab** in the popup.
- **Selected tabs** uses the **OpenClaw** tab group as the access-control
  boundary. Moving a tab into the group grants access; moving it out revokes
  access.

Open the extension's Settings page to change the access mode. Switching to
Selected tabs immediately detaches ungrouped tabs, including attaches already
in flight. Agent-created tabs stay in the OpenClaw group in either mode.

The extension excludes incognito tabs, internal pages such as `chrome://` and
`chrome-extension://`, and tabs without a usable current URL. `file://` access
also requires Chrome's **Allow access to file URLs** setting.

## Automatic setup controls

Settings shows redacted relay/native bootstrap status and an **Use automatic
local setup** switch.

- Turning automatic setup off preserves a valid existing pairing but prevents
  new native bootstrap attempts.
- **Disconnect and disable automatic setup** revokes the pairing immediately,
  detaches debugger sessions, and persists the opt-out.
- **Use local OpenClaw** clears the opt-out and retries the native host.
- Saving an explicit manual pairing also clears the opt-out.

Pre-release development installs that paired before local Gateway wakeup
routing keep their existing pairing unchanged. In Settings, use **Disconnect
and disable automatic setup**, then **Use local OpenClaw** to create the new
local pairing. Released builds do not require this recovery step.

### Upgrades from the retired tab copilot

If Settings says automation is paused to protect a pre-upgrade copilot
session, confirm that old runs are finished. Then click **Disconnect and
disable automatic setup** to discard the retired recovery state, followed by
**Use local OpenClaw** to reconnect. Until that explicit disconnect succeeds,
the extension preserves the retired state and blocks relay connections, native
setup, manual pairing, tab access changes, and debugger attachment.

Chromium caches the first missing-native-host result for the running browser
process. If an existing extension already attempted automatic setup before the
native host was installed, restart Chrome once (a full browser-process reload).
Retrying from the popup or Settings cannot clear that process-level miss.
Normal setup avoids it by pre-registering the host before **Load unpacked**.

## Status and removal

Inspect the installation without printing credentials:

```bash
openclaw browser extension status
openclaw browser extension status --json
```

Remove only OpenClaw-owned native-host manifests and launchers:

```bash
openclaw browser extension uninstall-host
```

This does not remove the unpacked extension from Chrome. Use
`chrome://extensions` for that. It also does not delete the stable extension
copy or an existing relay key.

`openclaw browser extension path` is read-only. It prints the stable installed
copy when present and the bundled source directory otherwise.

## Advanced manual pairing

The Settings page owns manual pairing. Generate a host-local pairing string:

```bash
openclaw browser extension pair
```

Manual pairing remains useful on Windows and for recovery. Treat the complete
pairing string as a password.

Without `--gateway-url`, this command retains the host-local `/extension` relay
for standalone manual pairing. It does not wake Browser control; the selected
profile relay must already be running before the extension connects.

For a laptop that has Chrome but does not run OpenClaw or a browser node, pair
directly to a remote Gateway:

```bash
openclaw browser extension pair \
  --gateway-url wss://gateway.example.com
```

Paste that string in **Settings → Advanced manual pairing**. This flow cannot
use automatic bootstrap: the remote Gateway owns a different relay key, and the
local native host never fetches or copies it. Non-loopback remote URLs require
`wss://`, and the Gateway must expose the exact `/browser/extension` WebSocket
path without a path-rewriting proxy prefix.

## External CDP clients

The relay supports Browser Relay Authentication v2 clients such as mcporter.
Print non-secret endpoint metadata:

```bash
openclaw browser extension cdp
openclaw browser extension cdp --json
```

The output includes the loopback endpoint, protocol version, key ID, and fixed
challenge/complete resources. It does not include the relay key or an
authorization header.

`cdp --legacy-bearer` is a temporary, warned compatibility escape hatch. It
works only while `browser.extensionRelay.allowLegacyAuth=true` and prints the
legacy credential on request.

## Permissions

The extension requests only:

- `debugger`: send CDP commands to allowed tabs;
- `tabs` and `tabGroups`: discover tabs and enforce access mode;
- `storage`: persist pairing, access mode, session pauses, and bootstrap opt-out;
- `alarms`: wake the MV3 worker for relay/bootstrap retries;
- `nativeMessaging`: request one local bootstrap pairing.

It does not request `activeTab`, `contextMenus`, `scripting`, or `sidePanel`.

## Native bootstrap security

The native host is `ai.openclaw.browser_bootstrap`. Each
`chrome.runtime.sendNativeMessage` call starts one process, reads one request,
writes one response, and exits.

The request uses a versioned, length-prefixed JSON frame with a fresh 16-byte
nonce. The host caps input at 4 KiB, requires fatal UTF-8 decoding and exact
fields, verifies the caller origin against the exact installed manifest, and
returns only a locally generated pairing or a bounded non-secret failure code.
The response is below Chrome's 1 MiB native-message limit. Pairing keys never
appear in launcher arguments, manifests, status JSON, or diagnostics.

The POSIX launcher and manifest use absolute canonical paths under an
OpenClaw-owned mode-`0700` directory. Manifests are mode `0600`; the launcher is
owner-executable. Symlinks, foreign ownership, unsafe modes, path traversal,
wildcard origins, and foreign same-name registrations fail closed.

The unpacked ID calculation matches Chromium's
`crx_file::id_util::GenerateIdForPath`: hash the canonical absolute path's raw
bytes with SHA-256 (native UTF-16LE path bytes on Windows, with only a lowercase
drive letter uppercased), keep the first 16 digest bytes, then map hexadecimal
digits `0` through `f` to letters `a` through `p`. The extension manifest has no
`key`; registration authorizes only exact IDs derived from approved
OpenClaw-owned realpaths.

The relay itself uses connection-bound HMAC proofs. The persistent per-host key
is not sent in a URL, header, WebSocket subprotocol, or application frame.

## Troubleshooting

```bash
openclaw browser extension status --json
openclaw browser doctor --browser-profile chrome
openclaw doctor
```

- **No extension ID detected:** keep Chrome running, rerun `extension install`,
  and use **Load unpacked** only after the command says native bootstrap is
  ready and prints the stable path.
- **Extension was loaded before native setup:** restart Chrome once to clear its
  cached native-host miss, then rerun the ordered install flow.
- **Waiting for local OpenClaw:** run `extension status`; install or repair the
  owned native host.
- **Automatic setup disabled:** enable it in Settings or click **Use local
  OpenClaw**.
- **Manual setup required:** use Settings for the advanced pairing flow. This
  is expected on Windows and direct extension-only remote Gateway setups.
- **Relay unavailable:** confirm `openclaw gateway run` or the managed Gateway
  service is running for local setup, or confirm the browser node is running
  for browser-node setup. Then run browser doctor. No separate browser prewarm
  should be necessary.

See [Browser](/tools/browser) for the full profile model and the managed
`openclaw` and Chrome MCP `user` profiles.
