chrome-remote-interface

A Node.js client for the Chrome DevTools Protocol, exposing every browser command, event, and type as a plain JavaScript API.

SDK
npm
v0.34.0
4,554stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
42/100Fair
Development Activity4
Maintenance0
Community64
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
67/100Good
Architecture78
Code Quality65
Innovation70
Learning Curve55

chrome-remote-interface is a lightweight Node.js module that connects to Chrome, Chromium, or any other implementation of the Chrome Debugging Protocol (CDP) over WebSocket and exposes the entire protocol surface — commands, events, and types across every domain — as a plain JavaScript API. Rather than hand-coding bindings for each CDP version, the library fetches the protocol descriptor at connect time (either the bundled copy or a live one from the target) and dynamically generates every method, so it stays current with new Chrome releases without code changes.

Beyond the raw client, the package ships a chrome-remote-interface CLI with subcommands for managing targets (listing, creating, activating, and closing tabs) and an interactive inspect REPL for running commands and binding events against a live browser with completion and embedded protocol documentation. It is widely used as the low-level foundation underneath browser automation, scraping, and custom-devtools tooling.

What You Get

  • A single CDP() factory that returns a live Chrome client connected over WebSocket, usable with either Node-style callbacks or Promises/async-await.
  • Full JavaScript bindings for every Chrome DevTools Protocol domain, command, event, and type, generated dynamically from the protocol descriptor at connect time.
  • A bundled chrome-remote-interface CLI with target management subcommands (list/new/activate/close) and an interactive inspect REPL with completion.
  • Support for either the bundled local protocol descriptor or a live-fetched remote one, so you can target older, patched, or non-Chrome CDP implementations.
  • A separate browser-bundle build (via webpack) in addition to the Node.js module, for running the same client from within a page context.

Common Use Cases

  • Driving headless Chrome for automated browser testing or scraping without pulling in a higher-level automation framework.
  • Building custom devtools, performance profilers, or network inspectors directly on top of the raw CDP event stream.
  • Automating page navigation, DOM inspection, and network monitoring from Node.js scripts and CI pipelines.
  • Debugging and prototyping Chrome DevTools Protocol command sequences interactively via the bundled REPL client.

Under The Hood

Architecture The module is structured as a thin layered facade: index.js exposes the CDP() factory function that wraps the internal Chrome class (lib/chrome.js) in either callback or Promise mode via an EventEmitter notifier, decoupling connection setup from consumption. Chrome composes three concerns — target resolution (_fetchDebuggerURL, supporting string ids, WebSocket URLs, objects, or selector functions), protocol acquisition (_fetchProtocol, either the bundled protocol.json or a live fetch via lib/devtools.js), and the WebSocket transport (_connectToWebSocket, _enqueueCommand, _handleMessage) — all sequenced through one async _start() method. Once connected, lib/api.js’s prepare() walks the fetched protocol descriptor and dynamically attaches every domain’s commands, events, and types onto the Chrome instance, so the object surface is generated at runtime from data rather than hand-written per domain. lib/devtools.js mirrors this callback/promise duality for the separate HTTP-based DevTools frontend (/json/list, /json/new, etc.) through a shared promisesWrapper helper. Because the entire command surface is protocol-driven, updating protocol.json is the main lever for supporting a new CDP version — the abstraction most other code depends on is prepare()’s runtime decoration.

Tech Stack Runtime dependencies are deliberately minimal: ws (^7.2.0) for the WebSocket client and commander (2.11.x) to drive the bundled CLI (bin/client.js). There’s no application framework — this is a plain CommonJS Node.js module (main: index.js, Node >=8) with a separate browser build (chrome-remote-interface.js) produced by webpack.config.js via webpack 5 and babel-loader/babel-preset-env, backed by browser shims (babel-polyfill, process, url, util) listed as devDependencies. There is no TypeScript, database, or ORM — the only external I/O is HTTP (via lib/external-request.js) and WebSocket. CI (.github/workflows/ci.yml) runs against a real headless Chrome instance launched with --remote-debugging-port, polling until it accepts connections before running the test suite.

Code Quality Tests live in test/ (connect.js, send.js, event.js, close.js, devtools.js) using mocha and Node’s built-in assert — this is integration-style testing against a real headless Chrome rather than unit tests with mocks, and there is no coverage tooling. Error handling is explicit: lib/errors.js defines a small ProtocolError subclass carrying the original request/response for CDP-level failures, while low-level WebSocket errors are distinguished via instanceof Error checks in chrome.js’s send(). The codebase has no TypeScript or JSDoc type annotations, just plain strict-mode ES2015+ CommonJS with consistent, terse naming (addCommand, addEvent, addType). An ESLint config (.eslintrc.json, run via scripts/run-linter.sh) enforces style, and CI runs the full real-Chrome suite on every push and pull request to master.

API Design The standout ergonomic feature is that the API needs no hand-written bindings for CDP’s many domains and commands: prepare() generates every method, event subscriber, and type helper at runtime from whatever protocol descriptor is loaded, so the library tracks new Chrome releases by swapping a data file rather than shipping code changes. Every generated function is further decorated with the original protocol metadata (parameter descriptions, $ref types, category), so inspecting a method like Page.navigate in a REPL surfaces its full documentation inline — a pattern reinforced by the bundled chrome-remote-interface inspect REPL with completion. Commands, events, and DevTools HTTP calls all transparently support both callback and Promise styles depending on whether a callback argument is supplied, so the same API reads naturally in older callback-style code and modern async/await alike. This is an ergonomic, thin wrapper generator over an existing, well-documented protocol rather than a novel wire-protocol implementation, but the developer experience it delivers is genuinely strong.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search