Skip to content

opzero1/chrome-devtools-cli

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Chrome DevTools CLI

Rust CLI that connects to an existing Chrome browser via the DevTools Protocol. Auto-connects by default — no manual WebSocket URL needed.

Installation

Homebrew (macOS)

brew tap opzero1/chrome-devtools-cli
brew install chrome-devtools

Build from source

cargo build --release
# Binary: ./target/release/chrome-devtools

Why this exists

Inspired by chrome-devtools-mcp — the official MCP server for Chrome DevTools. It works well, but MCP-based browser tools consume a lot of token context: every interaction sends and receives large protocol payloads through the MCP layer.

99% of the time the browser being controlled is the user's own Chrome with their own credentials, so there is no need for a full headless browser stack like Puppeteer or Playwright, and no need for the MCP overhead.

This is a lightweight Rust binary that talks directly to Chrome's DevTools Protocol. One command in, one result out. No separate browser process, no credential handoff, no heavyweight runtime. The agent skill for this tool is a single SKILL.md file — the entire context overhead is this documentation.

Architecture

chrome-devtools navigate https://example.com
        │
        ├─ Try daemon (Unix socket /tmp/chrome-devtools-daemon.sock)
        │   └─ If running → send command → get result
        │
        ├─ If no daemon → spawn one (background process)
        │   └─ Daemon connects to Chrome WebSocket (approval may appear here)
        │   └─ Listens on Unix socket, configurable idle timeout (default 5m)
        │
        └─ Fallback → direct WebSocket connection (no daemon)

The daemon keeps a persistent WebSocket connection while it is alive, so repeated commands usually reuse the same connection. If the daemon restarts (idle timeout/crash) or the CLI falls back to direct mode, Chrome may prompt for DevTools access again.

Prerequisites

Chrome must have remote debugging enabled:

  1. Open Chrome
  2. Go to chrome://inspect/#remote-debugging
  3. Enable the remote debugging server

Auto-connect

By default, the CLI reads DevToolsActivePort from Chrome's user data directory:

OS Default path
macOS ~/Library/Application Support/Google/Chrome/
Linux ~/.config/google-chrome/
Windows %LOCALAPPDATA%\Google\Chrome\User Data\

Override with --user-data-dir, --channel (beta/canary/dev), or --ws-endpoint.

Target-first page workflow

Every page-level command outputs a friendly target name like [target:red-snake]. This is a deterministic word-pair derived from Chrome's internal target ID — same page always gets the same name.

For multi-step automation, treat --target as required after your first page-discovery command (navigate or list-pages).

# Navigate — note the target name
chrome-devtools navigate https://example.com
# Navigated to https://example.com
# [target:red-snake]

# Pin subsequent commands to the same page
chrome-devtools --target red-snake screenshot --output /tmp/page.png
chrome-devtools --target red-snake evaluate "document.title"

Without --target, commands default to page index 0, which may vary as Chrome reorders tabs. Use unpinned commands only for one-off checks; for workflows, always capture and reuse the target name.

list-pages shows all pages with their friendly names:

[0] (green-dog) My App — https://localhost:3000
[1] (red-snake) Example Domain — https://example.com
[2] (bold-stag) GitHub — https://github.com

You can also use --page <index> for quick one-offs, or pass the raw hex target ID.

Commands

Navigation

Command Description
navigate <url> Go to URL (waits for load)
navigate --back Go back in history
navigate --forward Go forward
navigate --reload Reload page
new-page <url> Open new tab
close-page <index> Close tab by index
select-page <index> Bring tab to front
list-pages List all open tabs

Inspection

Command Description
screenshot --output <path> Save screenshot to file
screenshot --full-page Capture full scrollable page
record-video --output <path> Record page to MP4 video (requires ffmpeg)
evaluate <expr> Run JavaScript, return result
snapshot Accessibility tree dump

Interaction

Command Description
click <selector> Click element by CSS selector
fill <selector> <value> Fill input field
type-text <text> Type into focused element
press-key <key> Press key (e.g. Enter, Control+A)
hover <selector> Hover over element

Other

Command Description
resize <w> <h> Set viewport size
wait-for <text> [--timeout ms] Wait for text to appear (default 30s)

Video Recording

Record the visible page to an MP4 file. Requires ffmpeg in PATH.

# Record 5 seconds at default settings (12 fps, quality 80)
chrome-devtools --target red-snake record-video --output recording.mp4

# Record 10 seconds at higher quality and frame rate
chrome-devtools --target red-snake record-video --output demo.mp4 --duration 10 --fps 24 --quality 90

# Cap resolution to 1280x720
chrome-devtools --target red-snake record-video --output small.mp4 --width 1280 --height 720
Flag Default Description
--output / -o (required) Output MP4 file path
--duration 5 Recording duration in seconds
--fps 12 Target frames per second
--quality 80 JPEG quality for screencast frames (1-100)
--width (none) Max capture width
--height (none) Max capture height

Install ffmpeg: brew install ffmpeg (macOS), sudo apt install ffmpeg (Ubuntu), or see ffmpeg.org.

Global options

Flag Description
--target <name> Target page by friendly name or raw ID
--page <index> Target page by index
--json JSON output
--ws-endpoint <url> Explicit WebSocket URL
--user-data-dir <path> Custom Chrome profile directory
--channel <ch> Chrome channel (stable/beta/canary/dev)
--daemon-idle-timeout <value> Daemon idle timeout (30m, 1h, never, or Ns/Nm/Nh)

You can also set CHROME_DEVTOOLS_DAEMON_IDLE_TIMEOUT as an environment fallback.

Examples:

# Keep daemon alive for 30 minutes of inactivity
chrome-devtools --daemon-idle-timeout 30m list-pages

# Keep daemon alive for 1 hour (env fallback)
CHROME_DEVTOOLS_DAEMON_IDLE_TIMEOUT=1h chrome-devtools navigate https://example.com

# Disable idle shutdown
chrome-devtools --daemon-idle-timeout never snapshot

Daemon details

  • Socket: /tmp/chrome-devtools-daemon.sock
  • PID file: /tmp/chrome-devtools-daemon.pid
  • Idle timeout: 5 minutes by default (configurable via --daemon-idle-timeout or CHROME_DEVTOOLS_DAEMON_IDLE_TIMEOUT)
  • Protocol: Length-prefixed JSON over Unix socket
  • Spawned by: First CLI invocation (transparent to user)
  • Kill manually: pkill -f __daemon__ or delete the socket

If a daemon is already running, passing a new --daemon-idle-timeout updates it for future idle periods (no manual restart required).

Source layout

src/
├── main.rs         # CLI (clap) + daemon-first dispatch
├── cdp.rs          # Raw CDP over WebSocket (JSON-RPC)
├── browser.rs      # Auto-connect (DevToolsActivePort)
├── daemon.rs       # Background daemon (persistent connection)
├── client.rs       # Talks to daemon via Unix socket
├── protocol.rs     # IPC message types
├── friendly.rs     # Target ID → word-pair names
└── commands/
    ├── navigate.rs
    ├── pages.rs         # list/new/close/select/resize/wait-for
    ├── screenshot.rs
    ├── record_video.rs  # screencast → ffmpeg MP4
    ├── evaluate.rs
    ├── input.rs         # click/fill/type/press/hover
    └── snapshot.rs

Typical workflow (target-first)

# 1. Discover/select the page and capture [target:name]
chrome-devtools navigate https://example.com
# [target:red-snake] (save this)

# 2. From here on, always pin --target
chrome-devtools --target red-snake snapshot
chrome-devtools --target red-snake screenshot --output /tmp/page.png

# 3. Interact
chrome-devtools --target red-snake fill "#email" "user@example.com"
chrome-devtools --target red-snake click "#submit"

# 4. Extract data
chrome-devtools --target red-snake evaluate "document.title"

Always pass --target from step 2 onward to stay on the same page.

Releasing

Patch releases are tag-driven.

  1. Bump Cargo.toml and Formula/chrome-devtools.rb to the new patch version.
  2. Push a tag like v0.1.2.
  3. Let .github/workflows/release.yml upload chrome-devtools-macos-arm64.zip to the GitHub release.
  4. Compute the published zip sha256 and replace the formula placeholder before testing the tap install.
  5. Run the brew install/test smoke flow against the published asset.

Agent skill

skill/chrome-devtools/SKILL.md is a Claude Code skill that teaches the agent how to use this binary. Drop it into any Claude Code plugin's skills/ directory and set chrome-devtools to the binary path. The skill covers the full workflow, all commands, and the --target pinning pattern — everything needed to reliably automate Chrome without large context overhead.

License

MIT

About

Chrome DevTools Protocol CLI — auto-connects to existing Chrome

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Rust 97.2%
  • Python 2.0%
  • Ruby 0.8%