Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

chrome-cdp-wsl

TL;DR — control a Chrome or Edge browser running on Windows from inside WSL2 (Linux) over the Chrome DevTools Protocol (CDP): navigate, click, type, screenshot, run JavaScript, and scrape page text/HTML.

🤖 AI agents: see AGENTS.md for a machine-readable invocation guide and llms.txt for a quick index.

Browser automation usually means spinning up an ephemeral, empty profile (Playwright, Selenium). This instead attaches to a persistent Chrome/Edge instance you launched with --remote-debugging-port=9222. Because the profile persists across runs, logins and cookies you establish stay put — and you can watch and hand-control the same window an agent is driving. Point it at your main profile (close Chrome first) to drive your real session directly.

python3 chrome_cdp.py status
python3 chrome_cdp.py navigate "https://example.com"
python3 chrome_cdp.py screenshot /tmp/shot.png

How it works

WSL2 (Linux)                         Windows
────────────                         ───────
chrome_cdp.py
  │  resolves Windows host IP (from /etc/resolv.conf, or --host)
  │  HTTP  GET http://<host>:9222/json   ──►  Chrome/Edge (--remote-debugging-port=9222)
  │  opens a WebSocket to the tab's        │   persistent debug profile
  │  webSocketDebuggerUrl                   │
  │  sends CDP commands  ──────────────────►│   Page.navigate, Runtime.evaluate,
  │  receives results / screenshots ◄────────   Page.captureScreenshot, ...
  ▼
prints output / saves screenshot
  1. Chrome/Edge runs on Windows with --remote-debugging-port=9222.
  2. Tab management uses the HTTP /json* endpoints; page interaction uses a WebSocket to the tab's webSocketDebuggerUrl.
  3. From WSL2 the tool resolves the Windows host IP from the nameserver line in /etc/resolv.conf (override with --host / CHROME_CDP_HOST).
  4. Both Chrome and Edge speak CDP (both are Chromium-based).

Requirements

  • Windows 10/11 with WSL2
  • Chrome or Edge installed on Windows
  • Python 3.7+ inside WSL with two packages:
pip install -r requirements.txt    # requests, websocket-client

Setup

Start the browser with remote debugging enabled (the helper launches it on the Windows side via PowerShell):

bash scripts/start_chrome_cdp.sh

Chrome's debug port only listens on the Windows localhost by default. If WSL2 can't reach it, add a one-time Windows portproxy (elevated shell) so the WSL-facing interface forwards to it:

netsh interface portproxy add v4tov6 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=::1

Then verify from WSL:

python3 chrome_cdp.py status

Usage

Global flags --host, --port, --timeout go before the subcommand.

CDP="python3 chrome_cdp.py"

# Connection
$CDP status                              # check CDP connection (JSON)

# Tabs (HTTP)
$CDP list-tabs                           # list all open tabs
$CDP new-tab "https://example.com"       # open a new tab
$CDP switch-tab <tab_id>                 # activate a tab
$CDP close-tab <tab_id>                  # close a tab

# Navigation
$CDP navigate "https://example.com"              # open URL in a new tab
$CDP navigate "https://example.com" --tab-id X   # navigate an existing tab

# Page info
$CDP title                               # page title
$CDP url                                 # current URL
$CDP text                                # visible page text (innerText)
$CDP content                             # full page HTML (first 5000 chars)
$CDP screenshot /tmp/shot.png            # save a PNG screenshot

# JavaScript
$CDP js "document.title"
$CDP js "[...document.querySelectorAll('.price')].map(e => e.textContent)"

# Interaction (CSS selectors)
$CDP click "#submit-button"              # click an element
$CDP type "#search" "hello world"        # set an input's value
$CDP wait ".results"                     # wait for an element (default 10s)
$CDP wait ".results" --wait-timeout 20   # custom timeout

# Override host/port (before the subcommand)
$CDP --host 127.0.0.1 --port 9222 status

Most WebSocket commands accept --tab-id <id> to target a specific tab (otherwise the first page-type tab is used).

Use from your own scripts

import sys
sys.path.insert(0, "/path/to/chrome-cdp-wsl")
from chrome_cdp import ChromeCDP

chrome = ChromeCDP()                 # or ChromeCDP(host=..., port=..., timeout=...)
chrome.navigate("https://example.com")
chrome.screenshot("/tmp/shot.png")
title = chrome.get_title()
links = chrome.execute_js("[...document.querySelectorAll('a')].map(a => a.href)")
chrome.click("#submit-button")
chrome.type_text("#search", "hello")
chrome.wait_for(".results", timeout=10)
chrome.close()                       # tear down the WebSocket when done

Configuration

Variable Default Purpose
CHROME_CDP_HOST nameserver in /etc/resolv.conf Windows host address
CHROME_CDP_PORT 9222 Remote-debugging port
CHROME_PATH Chrome's default install path Browser exe (start script)
CHROME_DEBUG_PROFILE C:\chrome-debug-profile Debug profile dir (start script)

Troubleshooting

  • Connection failed — run python3 chrome_cdp.py status. If not connected, the browser isn't running with debugging (scripts/start_chrome_cdp.sh) or WSL2 can't reach the port (add the portproxy above, or try --host 127.0.0.1 under mirrored-mode WSL networking).
  • WebSocket 403 Forbidden — the browser needs --remote-allow-origins=* (the start script includes it).
  • Element not foundwait for it before click/type.

Security notes

An open remote-debugging port is an unauthenticated control channel into the browser session — anything that can reach port 9222 can act as that browser.

  • Only enable it on a machine you control; keep the port on the local WSL↔Windows link, not the wider LAN.
  • The 0.0.0.0 portproxy above exposes the port on all interfaces — restrict it with the firewall if your machine isn't on a trusted network.
  • Treat js like any code-execution path: don't pass it untrusted input.

Keywords

Chrome · Edge · Chromium · Chrome DevTools Protocol · CDP · WSL · WSL2 · browser automation · headful · remote debugging · --remote-debugging-port · persistent profile · logged-in session · WebSocket · screenshot · navigate · scrape · Playwright alternative · Linux-to-Windows

License

MIT — see LICENSE.

About

Control a Windows Chrome/Edge browser from WSL2 over the Chrome DevTools Protocol — attaches to a persistent debug profile (logins/cookies survive). Navigate, click, type, screenshot, run JS.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages