Reviewer test steps
These steps show Browser Control working, for Chrome Web Store reviewers and anyone else who wants to try it.
Browser Control does nothing until its local native messaging host is installed. Until then, the popup shows Disconnected. For other help, see Support.
What you need
- macOS or Linux, with Google Chrome™ 106 or later (
minimum_chrome_versioninmanifest.json). Use one Chrome profile with Browser Control turned on. All profiles share one host socket, so a second profile cannot connect at the same time. - Node.js 18 or later on the
PATH. Check withnode --version. The host is a Node.js program. curlandunzip. Both come with macOS. On Debian or Ubuntu:sudo apt-get install curl unzip.- Internet access to
browser-control.pages.dev(to download the helper) and tohttps://example.com/(for the demo page). - No account, sign-in, API key or server is needed.
ffmpegis not needed. - Windows is not covered by these steps. A host started by Chrome on Windows needs a private token file that the installer does not create.
Steps
1. Install the extension and see the idle state
- Install Browser Control.
- Click the Browser Control icon in the toolbar.
Expected: the popup shows Disconnected and "Install the native host to connect." Nothing else happens. The extension has no network code, so it stays idle until a host exists.
2. Download the helper
mkdir -p ~/browser-control-review
cd ~/browser-control-review
curl -fsSL -o chrome-control-skill.zip https://browser-control.pages.dev/download/chrome-control-skill.zip
unzip -o chrome-control-skill.zip -d helper
cd helper
ls
Expected: the folder contains SKILL.md, native-host/, scripts/ and chunks/. Run all later commands in this helper folder.
The link downloads chrome-control-skill.zip for version 0.2.1 from this website. The same file is built from the source at github.com/opzero1/browser-control.
3. Install the native messaging host
node scripts/install-native-host.js --extension-id dcnjjnecbhipdbngkhjppkckpkellmld
node scripts/check-native-host-manifest.js --json
Expected:
- The installer prints
Installed native messaging manifest:with the manifest path,Allowed extension origin: chrome-extension://dcnjjnecbhipdbngkhjppkckpkellmld/, andHost executable:with the path ofnative-host/opzero-chrome-host. - The check prints JSON with
"ok": trueand"status": "valid".
The manifest is written to ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.opzero.chrome.json on macOS, or ~/.config/google-chrome/NativeMessagingHosts/com.opzero.chrome.json on Linux.
4. Connect
- Open the Browser Control popup.
- Click Reload host.
Expected: the popup shows Connected and "Connected to the local agent host." If it still shows Disconnected, wait 30 seconds (the extension retries automatically) or click Reload host again.
5. Check the connection from the command line
node native-host/client.js ping
node native-host/client.js getInfo
Expected:
pingprints{"jsonrpc":"2.0","id":1,"result":"pong"}. The answer comes from the extension through the host.getInfoprints one JSON line with"version":"0.2.1","protocolVersion":2,"pageProtocolVersion":2and"extensionId":"dcnjjnecbhipdbngkhjppkckpkellmld".
If ping reports Extension protocol v2 is not ready, wait a few seconds and run it again. The host checks the extension for up to 10 seconds after it starts.
6. List open tabs (read only)
The client accepts request data only on standard input:
echo '{"jsonrpc":"2.0","id":1,"method":"getUserTabs","params":{}}' | node native-host/client.js --stdio
Expected: one JSON line whose result lists your open tabs with id, title, url, windowId and groupId. Chrome internal pages, such as chrome://extensions, are left out.
7. Open and read a tab
Save this file as review-demo.js in the helper folder:
const os = require("node:os");
const path = require("node:path");
const { ChromeTransport } = require("./native-host/transport.js");
const socket = process.env.OPZERO_CHROME_HOST_SOCKET || path.join(os.homedir(), ".opzero-chrome", "default.sock");
(async () => {
const browser = await ChromeTransport.connect(socket);
try {
const page = await browser.open("https://example.com/");
const snapshot = await browser.waitFor(page, { text: "Example Domain" }, 15000);
console.log(JSON.stringify({ url: snapshot.url, title: snapshot.title, text: snapshot.text.slice(0, 200), actions: snapshot.actions }, null, 2));
console.log("The tab stays open for 20 seconds. Click it in the \"Browser Control\" tab group to watch.");
await new Promise((resolve) => setTimeout(resolve, 20000));
} finally {
await browser.close();
}
})().catch((error) => {
console.error(error.message);
process.exit(1);
});
Then run:
node review-demo.js
Expected:
- A new background tab opens in a tab group named Browser Control.
- Chrome shows its notice that Browser Control is debugging the browser.
- The script prints JSON with
"url": "https://example.com/", the page title, the start of the visible text, and anactionslist with the page's link. - After 20 seconds the script ends and the extension closes the tab that it opened. Your own tabs stay as they were.
This uses the same client library (native-host/transport.js) that agent tools use. It opens the tab, attaches the debugger, binds the tab to https://example.com, navigates, and reads the page.
8. Pause and resume
- In the popup, click Pause host. The popup shows Paused, and the button changes to Resume host.
- Run
node native-host/client.js ping. It fails withPrivate client stopped; outcome may be unknown; do not replay, because pausing stops the host. - Click Resume host. The popup shows Connected again, and
pingprintspong.
9. Clean up
- Remove the extension on
chrome://extensions. - Remove the host manifest and the socket folder:
- macOS:
rm "$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.opzero.chrome.json" - Linux:
rm "$HOME/.config/google-chrome/NativeMessagingHosts/com.opzero.chrome.json" - Both:
rm -r "$HOME/.opzero-chrome" ~/browser-control-review
- macOS:
Where to look in the code
| Behavior | Source |
|---|---|
| Connection, reconnect and heartbeat | src/extension/background.ts, NativeTransport |
Request handlers (getUserTabs, createTab, observePage, capturePage, executeCdp and others) | src/extension/background.ts, the api object |
| Page reading and actions | src/extension/page-control.ts |
| Private credential fill | src/extension/private-input.ts |
| Cursor overlay | src/extension/content-scripts/opzero-chrome.ts |
| Native messaging host | src/native-host/host.ts |
| Command-line client and client library | src/native-host/client.ts, src/native-host/transport.ts |