This skill should be used when debugging web applications, diagnosing page errors, inspecting console output, or capturing screenshots of pages. It provides Chrome DevTools Protocol (CDP) automation via the chromectl.py script for collaborative or automated browser debugging.

0 stars
0 forks
Python
7 views

SKILL.md


name: chrome-debug description: This skill should be used when debugging web applications, diagnosing page errors, inspecting console output, or capturing screenshots of pages. It provides Chrome DevTools Protocol (CDP) automation via the chromectl.py script for collaborative or automated browser debugging.

Chrome Debug

Overview

This skill enables web application debugging through automated Chrome browser control using the Chrome DevTools Protocol (CDP). Use chromectl.py to launch Chrome instances, inspect pages, monitor console output, execute JavaScript, and capture screenshots—all from the command line.

The skill supports both collaborative debugging (visible Chrome window where developer and Claude work together) and automated debugging (headless background process for screenshot/console capture).

When to Use This Skill

Invoke this skill when:

  • Debugging web application issues or investigating page errors
  • Inspecting browser console for errors, warnings, or log messages
  • Capturing screenshots of pages to identify visual problems
  • Monitoring page behavior in real-time during development
  • Automating page inspection or testing workflows
  • Diagnosing JavaScript errors or unexpected page behavior

Do NOT use this skill for:

  • General web browsing or information gathering (use WebFetch instead)
  • Editing HTML/CSS files directly (this is for runtime inspection only)
  • Testing that requires sophisticated user interaction (use proper testing frameworks)

Critical: Headful vs Headless Mode

Always consider whether collaborative debugging or automation is needed:

Headful Mode (Default - No --headless flag)

scripts/chromectl.py start

When to use:

  • Collaborative debugging where developer can see and interact with the browser
  • Investigating visual issues that require manual inspection
  • Complex workflows where developer input is needed
  • Real-time troubleshooting sessions

Benefits:

  • Developer can interact manually while Claude monitors console/inspects state
  • Visual feedback for both developer and Claude
  • Easier to diagnose UI/layout issues together

Headless Mode (--headless flag)

scripts/chromectl.py start --headless

When to use:

  • Automated screenshot capture
  • Console monitoring without user interaction
  • Batch processing multiple pages
  • CI/CD or scripted testing scenarios

Benefits:

  • No visual window, runs in background
  • Faster, lighter weight
  • Suitable for automation

Default choice: Use headful mode for collaborative debugging unless automation is explicitly needed.

Debugging Workflows

Workflow 1: Collaborative Web App Debugging

Use when developer reports errors or unexpected behavior and wants to work together.

# 1. Start Chrome with visible window
scripts/chromectl.py start

# 2. Open the problematic page
TARGET=$(scripts/chromectl.py open https://myapp.com/problem-page | jq -r .id)

# 3. Start console monitoring in background
scripts/chromectl.py console-tail --id $TARGET --for 60 &

# 4. Take initial screenshot
scripts/chromectl.py screenshot --id $TARGET -o initial-state.png

# 5. Inspect page state using eval
scripts/chromectl.py eval --id $TARGET -e "document.readyState"
scripts/chromectl.py eval --id $TARGET -e "({
  title: document.title,
  errors: window.onerror ? 'Error handler present' : 'No error handler',
  scripts: document.scripts.length
})"

# 6. Developer can now interact with page while Claude monitors console output
# Claude watches console-tail output for errors while developer clicks/navigates

# 7. Clean up when done
scripts/chromectl.py stop

Workflow 2: Automated Screenshot & Console Capture

Use for quick automated inspection without collaboration.

# 1. Start headless Chrome
scripts/chromectl.py start --headless

# 2. Open page
TARGET=$(scripts/chromectl.py open https://example.com | jq -r .id)

# 3. Wait for page load
sleep 2

# 4. Capture full-page screenshot
scripts/chromectl.py screenshot --id $TARGET -o page.png --full-page

# 5. Check for JavaScript errors via eval
scripts/chromectl.py eval --id $TARGET -e "({
  title: document.title,
  url: location.href,
  readyState: document.readyState,
  hasErrors: typeof window.onerror !== 'undefined'
})"

# 6. Stop Chrome
scripts/chromectl.py stop

Workflow 3: Console Error Monitoring

Use when investigating intermittent errors or monitoring page activity.

# 1. Start Chrome (headful if developer wants to interact)
scripts/chromectl.py start

# 2. Open target page
TARGET=$(scripts/chromectl.py open https://myapp.com | jq -r .id)

# 3. Start console monitoring for extended period
scripts/chromectl.py console-tail --id $TARGET --for 120 > console-output.log &
TAIL_PID=$!

# 4. While console-tail runs, trigger actions or let developer interact
# Developer can click buttons, navigate, etc. while Claude monitors

# 5. Wait for monitoring to complete
wait $TAIL_PID

# 6. Analyze console-output.log for errors/warnings
grep -E '"console": "(error|warning)"' console-output.log

# 7. Clean up
scripts/chromectl.py stop

Workflow 4: Multiple Page Comparison

Use when comparing behavior across multiple pages or environments.

# 1. Start Chrome
scripts/chromectl.py start --headless

# 2. Open multiple pages
PROD=$(scripts/chromectl.py open https://app.com/page | jq -r .id)
STAGING=$(scripts/chromectl.py open https://staging.app.com/page | jq -r .id)

# 3. Wait for loads
sleep 3

# 4. Capture screenshots
scripts/chromectl.py screenshot --id $PROD -o prod.png
scripts/chromectl.py screenshot --id $STAGING -o staging.png

# 5. Compare page states
scripts/chromectl.py eval --id $PROD -e "document.querySelector('h1').innerText"
scripts/chromectl.py eval --id $STAGING -e "document.querySelector('h1').innerText"

# 6. Clean up
scripts/chromectl.py stop

JavaScript Evaluation for Debugging

The eval command is primarily for Claude's implicit use to inspect and debug page state. Use it to:

Inspect page state:

# Check if page loaded
eval --id $ID -e "document.readyState"

# Get page title and URL
eval --id $ID -e "({title: document.title, url: location.href})"

# Check for global variables
eval --id $ID -e "typeof myAppVariable"

# Inspect DOM elements
eval --id $ID -e "document.querySelector('#error-message')?.innerText"

Debug JavaScript functions:

# Check if function exists
eval --id $ID -e "typeof myFunction"

# Call function and inspect result
eval --id $ID -e "myFunction(testData)"

# Inspect object properties
eval --id $ID -e "window.myApp.config"

Trigger page actions (for debugging):

# Click element to reproduce error
eval --id $ID -e "document.querySelector('button#submit').click()"

# Scroll to bottom
eval --id $ID -e "window.scrollTo(0, document.body.scrollHeight)"

# Fill form field
eval --id $ID -e "document.querySelector('input#email').value = '[email protected]'"

Note: Evaluation supports promises automatically, so async operations work seamlessly.

Important Reminders

Always Stop Chrome When Done

scripts/chromectl.py stop

Critical: Headless Chrome instances run invisibly and can prevent normal Chrome from launching. Always run stop at the end of debugging sessions.

Console-Tail Only Captures New Messages

The console-tail command only captures console messages that occur AFTER the command starts. Historical messages are not shown.

Pattern for effective console monitoring:

# Start monitoring FIRST
scripts/chromectl.py console-tail --id $TARGET --for 30 &

# THEN trigger actions that generate console output
scripts/chromectl.py eval --id $TARGET -e "myFunction()"

Multiple Chrome Instances

Can run multiple debugging instances on different ports:

# Instance 1
scripts/chromectl.py start --port 9222

# Instance 2 (different port and profile)
scripts/chromectl.py start --port 9223 --user-data-dir ~/chromectl-debug2

# Use instance 2
scripts/chromectl.py --port 9223 list

Extract Target IDs

Target IDs are needed for eval, screenshot, and console-tail commands:

# Extract ID from open command
TARGET=$(scripts/chromectl.py open https://example.com | jq -r .id)

# Or list all targets and manually select
scripts/chromectl.py list

Resources

scripts/chromectl.py

The main Chrome debugging utility. A self-contained Python script using uv for dependency management (aiohttp). Communicates with Chrome via the DevTools Protocol.

Execute from skill directory:

scripts/chromectl.py <command> [options]

references/chromectl-reference.md

Complete command reference with all options, examples, and troubleshooting guidance. Consult this for:

  • Detailed command syntax
  • Advanced usage patterns
  • Troubleshooting connection issues
  • Technical details about CDP

Quick Reference

Common command patterns:

# Start debugging session
scripts/chromectl.py start                    # Visible window (collaborative)
scripts/chromectl.py start --headless         # Background (automation)

# Get target ID
TARGET=$(scripts/chromectl.py open URL | jq -r .id)

# Monitor console
scripts/chromectl.py console-tail --id $TARGET --for 30

# Capture screenshot
scripts/chromectl.py screenshot --id $TARGET -o file.png

# Inspect page state
scripts/chromectl.py eval --id $TARGET -e "expression"

# Always clean up
scripts/chromectl.py stop

Troubleshooting:

# Verify Chrome is running
lsof -i :9222

# List all targets
scripts/chromectl.py list

# Test CDP connection
curl http://localhost:9222/json

README

Chrome Debug Skill for Claude Code

A Claude Code skill and standalone CLI tool for controlling Chrome via the Chrome DevTools Protocol (CDP). Enables automated web app debugging, console monitoring, and screenshot capture.

Built as a single-file Python script using uv inline dependencies — no requirements.txt, no manual venv, no setup required.

Use it as:

  • 🤖 Claude Code Skill - Claude automatically debugs your web apps
  • 🛠️ Standalone Tool - Command-line Chrome automation via chromectl.py

Features

  • Zero-setup: Just run the script, uv handles all dependencies automatically
  • Browser automation: Open tabs, evaluate JavaScript, capture screenshots
  • Console monitoring: Stream live console messages from any tab
  • Full-page screenshots: Capture entire pages, not just the viewport
  • Headless support: Run Chrome in the background without a visible window

Install as Claude Code Skill

Want Claude to help debug your web apps automatically? Install this as a skill for Claude Code.

Quick Install

cd ~/.claude/skills
git clone https://github.com/pengelbrecht/chrome-debug-skill.git chrome-debug

Then restart Claude Code.

What does the skill do?

Once installed, Claude will automatically use this skill when you ask for help with:

  • "Debug why this page isn't loading correctly"
  • "Take a screenshot of https://example.com"
  • "Check the console for errors on my webapp"
  • "Monitor console output while I test my app"

The skill enables collaborative debugging where Claude can:

  • Launch Chrome in visible mode (so you can interact with the page)
  • Monitor console errors in real-time
  • Capture screenshots to identify visual issues
  • Execute JavaScript to inspect page state
  • All while you navigate and test your application

See SKILL.md for complete skill documentation and workflows.


Standalone Installation (Without Claude Code)

Clone the repository and use the script directly:

git clone https://github.com/pengelbrecht/chrome-debug-skill.git
cd chrome-debug-skill
chmod +x scripts/chromectl.py

That's it! On first run, uv will automatically install the required dependency (aiohttp).

Quick Start

  1. Launch Chrome with remote debugging:

    scripts/chromectl.py start --headless
    
  2. List all open tabs:

    scripts/chromectl.py list
    
  3. Open a new tab:

    scripts/chromectl.py open https://example.com
    # Output: {"id":"ABC123...","url":"https://example.com"}
    
  4. Run JavaScript:

    scripts/chromectl.py eval --id ABC123 -e "document.title"
    # Output: "Example Domain"
    
  5. Stop Chrome when done (important!):

    scripts/chromectl.py stop
    

    ⚠️ Always run stop when finished to clean up Chrome processes and allow normal Chrome to launch from Finder.

Commands

start - Launch Chrome with debugging enabled

scripts/chromectl.py start [--headless] [--port PORT] [--chrome-app NAME] [--user-data-dir PATH]

Options:

  • --headless - Run Chrome in headless mode (no visible window)
  • --port - Remote debugging port (default: 9222)
  • --chrome-app - macOS app name (default: "Google Chrome")
  • --user-data-dir - Custom profile directory (default: ~/chromectl-profile)

Important: Each debugging instance uses a separate profile directory, allowing you to run multiple instances simultaneously without closing your regular Chrome browser.

Examples:

# Headless mode (recommended for automation)
scripts/chromectl.py start --headless

# Visible Chrome window
scripts/chromectl.py start

# Use Chrome Canary
scripts/chromectl.py start --chrome-app "Google Chrome Canary"

stop - Stop all chromectl-managed Chrome instances

scripts/chromectl.py stop

Finds and stops all Chrome instances launched by chromectl (identifies them by the chromectl profile directories).

Why use this:

  • Cleans up background Chrome processes
  • Frees up debugging ports (9222, etc.)
  • Allows you to launch regular Chrome from macOS Finder
  • Prevents interference with your normal Chrome usage

Output:

Stopping Chrome instance (PID: 5595)
Stopping Chrome instance (PID: 5602)
...
Stopped 8 Chrome instance(s)

Important: Always run stop when you're done debugging. Headless Chrome instances run invisibly in the background and can prevent normal Chrome from launching properly.


list - List all open tabs/targets

scripts/chromectl.py list

Shows all available targets (tabs, extensions, service workers) with their IDs, URLs, and titles.

Output format: One JSON object per line

{"id": "ABC123...", "type": "page", "title": "Example", "url": "https://example.com", "attached": null}

open - Open a new tab

scripts/chromectl.py open <url>

Opens a new tab at the specified URL and returns its target ID.

Examples:

# Open a website
scripts/chromectl.py open https://github.com

# Open a data URL with inline HTML/JS
scripts/chromectl.py open "data:text/html,<h1>Hello</h1>"

Tip: Save the target ID for use with other commands:

TARGET=$(scripts/chromectl.py open https://example.com | jq -r .id)
scripts/chromectl.py eval --id $TARGET -e "document.title"

eval - Evaluate JavaScript

scripts/chromectl.py eval --id <target-id> -e <expression>

Executes JavaScript in the specified tab and returns the result.

Features:

  • Automatically awaits promises (awaitPromise: true)
  • Returns JSON-serialized values
  • REPL mode enabled for cleaner output

Examples:

# Get page title
scripts/chromectl.py eval --id ABC123 -e "document.title"

# Get current URL
scripts/chromectl.py eval --id ABC123 -e "window.location.href"

# Return an object
scripts/chromectl.py eval --id ABC123 -e "({title: document.title, url: location.href})"

# Async operations work automatically
scripts/chromectl.py eval --id ABC123 -e "fetch('https://api.github.com').then(r => r.json())"

# DOM manipulation
scripts/chromectl.py eval --id ABC123 -e "document.querySelector('h1').innerText"

screenshot - Capture a PNG screenshot

scripts/chromectl.py screenshot --id <target-id> [-o output.png] [--full-page]

Options:

  • -o, --output - Output file path (default: screenshot_<id>.png)
  • --full-page - Capture entire page by resizing viewport to content height

Examples:

# Viewport screenshot (visible area only)
scripts/chromectl.py screenshot --id ABC123 -o page.png

# Full-page screenshot (entire scrollable content)
scripts/chromectl.py screenshot --id ABC123 -o fullpage.png --full-page

Output: Prints the filename when complete

page.png

console-tail - Stream console messages

scripts/chromectl.py console-tail --id <target-id> [--for SECONDS]

Streams console output from the specified tab in real-time.

Options:

  • --for - Duration in seconds to stream (default: 10)

Important: Only captures messages logged after the command starts. Historical console messages are not shown.

Output format: One JSON object per line

{"t": "+2.011s", "console": "log", "args": ["Test message"]}
{"t": "+2.015s", "console": "warning", "args": ["Warning text"]}
{"t": "+2.020s", "console": "error", "args": ["Error message"]}

Usage pattern:

# Start tailing in the background
scripts/chromectl.py console-tail --id ABC123 --for 30 &

# Then interact with the page
scripts/chromectl.py eval --id ABC123 -e "console.log('Hello from eval')"

Example: Monitor a page with active logging

# Open a page that logs continuously
scripts/chromectl.py open "data:text/html,<script>setInterval(() => console.log('tick', Date.now()), 1000)</script>"

# Start monitoring (captures new messages for 10 seconds)
scripts/chromectl.py console-tail --id <target-id> --for 10

How It Works

  • Shebang magic: #!/usr/bin/env -S uv run tells your shell to execute via uv run
  • Inline dependencies: The # /// script block (PEP 723) embeds dependency info directly in the file
  • Auto-caching: On first run, uv resolves and caches aiohttp (~17ms after initial install)
  • Chrome DevTools Protocol: Communicates with Chrome over HTTP and WebSocket on port 9222

Tips & Tricks

Run multiple debugging instances

You can run multiple Chrome instances simultaneously without closing your regular browser:

# Instance 1 on port 9222
scripts/chromectl.py start --headless

# Instance 2 on port 9223 (doesn't interfere with your regular Chrome)
scripts/chromectl.py start --headless --port 9223 --user-data-dir ~/chromectl-test

# Use the second instance
scripts/chromectl.py --port 9223 list

Closing Chrome cleanly

# Use the built-in stop command (recommended)
scripts/chromectl.py stop

# Or manually close all Chrome instances
killall "Google Chrome"

# Or find and kill specific debugging instance by PID
ps aux | grep chromectl-profile
kill <PID>

Chain commands with jq

# Open, capture ID, and screenshot in one go
TARGET=$(scripts/chromectl.py open https://github.com | jq -r .id)
scripts/chromectl.py screenshot --id $TARGET -o github.png

Monitor console while running tests

# Terminal 1: Start console monitoring
scripts/chromectl.py console-tail --id ABC123 --for 60

# Terminal 2: Run your automation
scripts/chromectl.py eval --id ABC123 -e "runTests()"

Debug connection issues

# Check if Chrome is listening on the debug port
lsof -i :9222

# Test HTTP endpoint directly
curl http://localhost:9222/json | jq .

Troubleshooting

"Cannot connect to host 127.0.0.1:9222"

  • No Chrome instance with remote debugging is running on that port
  • Start one with: ./chromectl.py start --headless
  • If port is taken, use a different port: ./chromectl.py start --headless --port 9223

"Target not found"

  • The tab was closed or the ID is incorrect
  • Run ./chromectl.py list to get current target IDs

Port already in use

  • Another Chrome instance is using port 9222
  • Use --port 9223 to specify a different port

Requirements

  • macOS (uses open -a to launch Chrome; Linux/Windows need different launch commands)
  • uv (Install here)
  • Google Chrome installed in /Applications/

License

MIT