Model or dataset
browser-use/browser-harness-js avatar
browser-use/browser-harness-js

browser-harness-js: a typed CDP bridge with no click() helper

Self-healing browser harness that enables LLMs to complete any task

484 stars39 forksTypeScriptMIT

At a glance

What is it?
Browser Harness JS exposes all 652 Chrome DevTools Protocol methods as typed JavaScript calls and deliberately omits convenience wrappers. It suits agents and engineers who already know CDP; it is the wrong layer for anyone who wants a page-object API.
Who is it for?
Adopt browser-harness-js if your agent or script already speaks CDP and you want the full 652-method surface without a wrapper deciding which parameters matter. Do not adopt it if you need a stable page abstraction, because there is no click() or goto() to fall back on and every call is a raw protocol method.
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 16 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

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

DEEP OPEN-SOURCE ANALYSIS

The problem: helpers that hide CDP parameters

Most browser automation layers sit between an agent and Chrome and decide in advance which parts of the protocol matter. A click(x, y) function is the usual example. The README makes the argument directly: that helper hides Input.dispatchMouseEvent, which the README says has 14 parameters, including button, clickCount, modifiers, pointerType, force and tangentialPressure. A wrapper that exposes three of them caps what the agent can express, and when the agent needs the fourth parameter it has to leave the abstraction anyway. Browser Harness JS takes the opposite position. The README states there is no harness, no recipes and no rails, just every CDP method as a typed JS call, and that the protocol is the API. The audience is narrow and specific: people building LLM agents that are allowed to write protocol calls themselves, and engineers who treat the CDP reference as the documentation rather than a framework's own docs. If you want a page-object model, this project is pointed away from you on purpose.

One WebSocket, 652 generated wrappers

The mechanism is code generation, not runtime magic. According to the file list, sdk/gen.ts reads browser_protocol.json and js_protocol.json and emits sdk/generated.ts, where every CDP method appears as session.<Domain>.<method>(params). The README puts the count at 56 domains and 652 typed wrappers. Transport lives in sdk/session.ts, described as the Session class handling transport, connect, target routing and events, and sdk/repl.ts is a Bun HTTP server that holds one persistent Session. The CLI, sdk/browser-harness-js, auto-spawns the server and forwards snippets to it. That single persistent connection is the architectural choice worth noticing: state such as the attached target and any event listeners survives between snippets, which is what makes an agent loop practical rather than reconnecting per step. The README names exactly four additions on top of raw CDP: listPageTargets(), which filters chrome:// and devtools:// out of Target.getTargets; resolveWsUrl({wsUrl|port|profileDir}), which reads DevToolsActivePort for Chrome 144 and later; session.use(targetId); and session.waitFor(method, pred, timeout). Everything else is the protocol. Because generated.ts is produced from upstream JSON, swapping in a newer protocol file is the documented way to pick up new Chrome methods.

Installing it as an agent skill

There is no npm package name in the README. Distribution is through a skills command: npx skills add https://github.com/browser-use/browser-harness-js --skill cdp. The README also supplies a paste-ready prompt for an agent, which instructs it to run that same command, symlink browser-harness-js into a directory on PATH, and then use the cdp skill to look at open tabs, group them by topic, and screenshot the most interesting one. Two environment details are stated. The CLI auto-installs bun on first run if it is missing, and setting BROWSER_HARNESS_SKIP_BUN_INSTALL=1 opts out of that. Chrome may ask you to tick a remote-debugging checkbox, which is how the agent attaches, and the README points at docs/setup-remote-debugging.png for that step. The README does not document a browser launch command, a port flag, or a config file beyond the resolveWsUrl parameters, so plan on supplying wsUrl, port, or profileDir yourself when you connect.

The cost of no click() helper

Removing wrappers moves work to the caller, and the README is honest that this is the design rather than an oversight. An agent that wants to click a button must construct Input.dispatchMouseEvent with the right coordinates, button, clickCount and modifier state. An agent that wants to attach a file must call DOM.setFileInputFiles. There is no goto(), so navigation is Page.navigate. The README acknowledges that some mechanics are not obvious from the method list alone and points to the interaction-skills/ directory for those recipes, with guidance to keep them in pure CDP and lead with the shortest working call. That directory is the pressure valve for the missing abstraction, and its contents are community-contributed rather than part of the core surface. The practical consequence is that reliability depends on the model's knowledge of CDP and on how well the typed signatures steer it. Types are presented as the documentation, with the same JSDoc as the CDP reference, but a type signature tells you the shape of a call, not the order of calls needed to make a framework dropdown behave.

Where a different layer fits better

Playwright is the obvious comparison, and the difference is not quality but altitude. Playwright ships the helpers this project refuses to write: locators, auto-waiting, and a page object that resolves selectors for you. Its API is a curated subset of what the browser can do, chosen so that common flows need one line. Browser Harness JS exposes the superset. If your task is a stable script against a known site, Playwright's auto-waiting removes an entire class of race conditions that a raw CDP caller has to handle through session.waitFor(method, pred, timeout) or its own polling. If your task is open-ended and the model keeps hitting the edge of the helper set, the raw surface stops being a liability. The two are not mutually exclusive in a stack, but they encode opposite assumptions about who decides which protocol parameters matter: the framework author or the agent at runtime.

Maintenance, licence and what to verify

The licence is MIT, which permits commercial use and modification provided the copyright notice and permission notice are retained; that is a summary of the identifier, not legal advice, and you should read the LICENSE file in the repository. Maintenance cost concentrates in two places. First, sdk/generated.ts is produced by codegen, so upgrading to a newer Chrome protocol is a regeneration step rather than hand edits, and the README frames that as the reason there is no version drift. Second, the routing and transport code in sdk/session.ts is hand-written, so that is where behavioural changes land. The repository shows no releases in the supplied material, so there is no versioned changelog to diff against and no published upgrade path; track the default branch instead. The README explicitly invites pull requests for codegen improvements and session.ts refinements, which suggests the maintainers expect those two files to keep moving. Verify the protocol JSON you regenerate from matches the Chrome build you actually attach to before trusting the generated signatures.

Editorial conclusion

Adopt browser-harness-js if your agent or script already speaks CDP and you want the full 652-method surface without a wrapper deciding which parameters matter. Do not adopt it if you need a stable page abstraction, because there is no click() or goto() to fall back on and every call is a raw protocol method. Before wiring it into anything, confirm three things: that your Chrome build exposes the remote debugging checkbox the README shows, that you can regenerate sdk/generated.ts from your own browser_protocol.json and js_protocol.json, and that you accept the MIT licence terms for your distribution. The first task to run is the README's own prompt, which lists open tabs, groups them by topic, and screenshots one, because that exercises target listing, session routing, and a domain call in a single pass.

Official sources

  1. browser-use/browser-harness-js on GitHub
  2. Issues
  3. License: MIT
  4. README
Community notes

Community notes