Launch Chrome with remote debugging enabled: `google-chrome --headless --remote-debugging-port=9222 --disable-gpu`. The browser exposes a WebSocket endpoint at `http://localhost:9222/json`.
Fetch the list of available targets from `http://localhost:9222/json/list` to get the WebSocket debugger URL for a specific tab, then open a WebSocket connection to that URL.
Send CDP commands as JSON objects with the shape `{ id: <number>, method: 'Domain.method', params: { ... } }` and read responses that match by `id`.
Enable necessary domains before using them — for example send `{ method: 'Page.enable' }` before listening for `Page.loadEventFired`, and `{ method: 'Network.enable' }` before intercepting network events.
Use the `Runtime.evaluate` command to run JavaScript in the page context and retrieve the result, and `Page.captureScreenshot` to take a screenshot without any library abstraction.
Known gotchas
CDP is stateful per session — domains you enable and event listeners you register persist for the lifetime of the WebSocket connection. If you reconnect (e.g., after a crash), you must re-enable all domains.
Chrome's CDP endpoint only binds to localhost by default. Exposing `--remote-debugging-address=0.0.0.0` in a shared environment creates a serious security risk — anyone on the network can execute arbitrary JavaScript in the browser.
CDP command IDs must be unique integers per connection; responses are asynchronous and may arrive out of order. You are responsible for correlating responses to requests, which is a significant amount of bookkeeping that high-level libraries handle for you.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp