Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
12dcc69
feat: add extra-headers, geolocation emulation, and unknown arg valid…
aeroxy May 24, 2026
45da69f
fix: harden argument validation and geolocation input checks
aeroxy May 25, 2026
d91b73f
feat: unify emulation into emulate command, add getters, fix help
aeroxy May 25, 2026
3efdec4
feat: unified emulation and atomic navigation support
aeroxy May 25, 2026
8323a1d
feat: unified emulation and atomic navigation support
aeroxy May 25, 2026
3348081
fix: subcommand detection logic in CLI help dispatch
aeroxy May 25, 2026
7f450ab
refactor: enhance emulation robustness and page management
aeroxy May 25, 2026
cb45c7b
fix: skill
aeroxy May 25, 2026
8c99518
feat: add mobile & device-scale-factor emulation flags, improve error…
aeroxy May 25, 2026
5f3f48e
fix: validate emulation flags and improve error handling
aeroxy May 25, 2026
6b44072
refactor: centralize validation, deduplicate header logic, fix new-pa…
aeroxy May 26, 2026
d7a646c
fix: retry on transient execution context errors during navigation wait
aeroxy May 26, 2026
2184fd2
fix: include clear_viewport and clear_geolocation in emulation flag c…
aeroxy May 26, 2026
170f2a9
fix: add emulation input validation and improve error handling
aeroxy May 26, 2026
0c19afb
fix: prevent target leak on attach failure and harden arg/index parsing
aeroxy May 26, 2026
b6918ec
fix: correct output handling in do_reload function
aeroxy May 26, 2026
a509dcb
refactor: CLI structure and command handling
aeroxy May 26, 2026
0aa4be3
fix: improve viewport and geolocation parsing by trimming whitespace
aeroxy May 26, 2026
63f332c
fix: enhance navigation command validation and add clear extra header…
aeroxy May 26, 2026
0dc0eed
fix: conditionally clear extra headers in navigate function and disab…
aeroxy May 26, 2026
ea64338
fix: enhance validation for device_scale_factor and accuracy in Emula…
aeroxy May 26, 2026
6855b31
fix: enhance header value validation in apply_extra_headers function
aeroxy May 26, 2026
c539b35
fix: enhance friendly name usage in close_page and select_page functions
aeroxy May 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 47 additions & 195 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,22 @@
# Chrome DevTools CLI
# 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.
A high-performance, developer-friendly CLI for interacting with Chrome via the DevTools Protocol (CDP).

[![crates.io](https://img.shields.io/crates/v/chrome-devtools-cli.svg)](https://crates.io/crates/chrome-devtools-cli)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/aeroxy/chrome-devtools-cli)
## Key Features

## Installation

### Homebrew (macOS, recommended)

```bash
brew install aeroxy/tap/chrome-devtools
```

### Cargo

```bash
cargo install chrome-devtools-cli
```
- **Page Emulation**: Manage viewport size, mobile device emulation, device scale factor, and geolocation overrides in one place.
- **Smart Navigation**: URL navigation, back/forward, and reload with automatic page-load waiting and custom HTTP headers.
- **Visual Tools**: High-quality screenshots (including full-page) and accessibility tree snapshots.
- **Interaction**: Click, fill, type, and hover using CSS selectors or coordinates.
- **JS Evaluation**: Run JavaScript on the page with support for handling dialogs.
- **3rd Party Integration**: Access tools exposed by pages via custom protocol extensions.

The installed binary is named `chrome-devtools`.

### Build from source
## Installation

```bash
cargo build --release
# Binary: ./target/release/chrome-devtools
cargo install --path .
```

## Why this exists

Inspired by [chrome-devtools-mcp](https://github.com/ChromeDevTools/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 (one-time approval)
│ └─ Listens on Unix socket, 5-min idle timeout
└─ Fallback → direct WebSocket connection (no daemon)
```

The daemon keeps a persistent WebSocket connection to Chrome, so the browser only prompts for DevTools access once. Subsequent commands reuse the connection.

## Prerequisites

Chrome must have remote debugging enabled:
Expand All @@ -62,168 +25,57 @@ Chrome must have remote debugging enabled:
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`. All three also read from environment variables:

| Environment Variable | Corresponding Flag |
|----------------------|--------------------|
| `CHROME_WS_ENDPOINT` | `--ws-endpoint` |
| `CHROME_USER_DATA_DIR` | `--user-data-dir` |
| `CHROME_CHANNEL` | `--channel` |

## Page targeting

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.
## Quick Start

### General Usage
```bash
# 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"
chrome-devtools list-pages
chrome-devtools --page 0 navigate https://google.com
chrome-devtools --target main screenshot --output screenshot.png
```

Without `--target`, commands default to page index 0, which may vary as Chrome reorders tabs. Always capture and reuse the target name.

`list-pages` shows all pages with their friendly names:
### Emulation (Page-level Overrides)
Overrides like viewport size and geolocation are persistent per page.

```
[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
```bash
# Set viewport and geolocation
chrome-devtools emulate --viewport 1280x720 --geolocation 37.77,-122.41

### Navigation
# Emulate mobile device
chrome-devtools emulate --viewport 375x812 --mobile --device-scale-factor 3

| 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 |
# Navigate with emulation
chrome-devtools navigate https://example.com --viewport 1920x1080 --mobile

### Inspection
# Open new tab with emulation
chrome-devtools new-page https://example.com --viewport 375x812 --geolocation 40.71,-74.00

| Command | Description |
|---------|-------------|
| `screenshot --output <path>` | Save screenshot to file |
| `screenshot --full-page` | Capture full scrollable page |
| `evaluate <expr> [--dialog-action <action>]` | Run JavaScript (optionally handle dialogs: accept, dismiss, or prompt text) |
| `snapshot` | Accessibility tree dump |
# Clear overrides
chrome-devtools emulate --clear-all
chrome-devtools emulate --clear-viewport
chrome-devtools emulate --clear-geolocation
```

### Interaction

| Command | Description |
|---------|-------------|
| `click <selector>` | Click element by CSS selector |
| `click-at <x> <y>` | Click at specific coordinates |
| `fill <selector> <value>` | Fill input field, dropdown (`<select>`), or toggle checkbox/radio (`"true"`/`"false"`) |
| `type-text <text> [--submit-key <key>]` | Type into focused element (optionally press key after) |
| `press-key <key>` | Press key (e.g. `Enter`, `Control+A`) |
| `hover <selector>` | Hover over element |

### Third-party developer tools

| Command | Description |
|---------|-------------|
| `list-3p-tools` | List custom developer tools exposed via `window.__dtmcp` |
| `execute-3p-tool <name> <params>` | Execute a custom tool by name with a JSON params string |

These commands interact with tools injected into the page via `window.__dtmcp.toolGroup` / `window.__dtmcp.executeTool`.

### Other

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

## 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 details

- **Socket**: `/tmp/chrome-devtools-daemon.sock`
- **PID file**: `/tmp/chrome-devtools-daemon.pid`
- **Idle timeout**: 5 minutes (auto-exits, cleans up socket)
- **Protocol**: Length-prefixed JSON over Unix socket
- **Spawned by**: First CLI invocation (transparent to user)
- **Kill manually**: `pkill -f __daemon__` or delete the socket

## 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
├── evaluate.rs
├── input.rs # click/fill/type/press/hover
├── snapshot.rs
└── third_party.rs # list-3p-tools/execute-3p-tool
```bash
chrome-devtools click "button.submit"
chrome-devtools fill "input[name='q']" "searching for something"
chrome-devtools type-text "submitting now" --submit-key Enter
```

## Typical workflow

### Custom HTTP Headers
```bash
# 1. Navigate — capture the [target:name]
chrome-devtools navigate https://example.com
# [target:red-snake]

# 2. Understand the page
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"
# Add authorization header
chrome-devtools navigate https://api.example.com --extra-headers '{"Authorization":"Bearer token"}'

# 4. Extract data
chrome-devtools --target red-snake evaluate "document.title"
# Debug headers
chrome-devtools new-page https://example.com --extra-headers '{"X-Debug":"1"}'
```

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

## 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
## Global Options

MIT
- `--ws-endpoint`: Use an explicit WebSocket URL.
- `--user-data-dir`: Auto-connect to a running Chrome instance.
- `--page <index>`: Select page by 0-based index.
- `--target <id>`: Select page by friendly name or ID.
- `--json`: Format output as JSON.
Comment thread
aeroxy marked this conversation as resolved.
Loading