Skip to content
audiotale.net
Sign in
AI learningExplainer

What is the Chrome DevTools Protocol (CDP)? How Puppeteer, Playwright and AI agents drive a browser

CDP is the JSON channel behind Puppeteer, Playwright's raw sessions and several AI-agent browsers; how it works, how to try it, and why Chrome 136 changed its debugging switches.

audiotale.net team

· 7 min read

Written by AI from the sources linked below. How we use AI

On this page
  1. In short
  2. Why this matters now
  3. What CDP is
  4. What a conversation looks like
  5. How you connect
  6. Why agents like it, and what they should be careful about
  7. The security side
  8. Quick reference
  9. What we could not confirm
  10. Sources

In short

The Chrome DevTools Protocol (CDP) is the JSON-based control channel that lets a program inspect and drive a Chromium-based browser: open a page, navigate, click, read the page's structure, take a screenshot, read cookies. Puppeteer speaks it, Playwright can speak it, and a growing number of AI-agent browsers and tools expose it so existing scripts keep working. It is powerful because it is complete, and risky for the same reason: whoever can reach a browser's debugging port controls that browser, including any logged-in sessions.

Why this matters now

CDP used to be something you met only in a test suite or in the Chrome DevTools panel. Agents changed that. A coding or research agent that browses needs a way to load pages, run scripts and capture results, and CDP is the common language. On 13 November 2026 Cloudflare open-sourced Kitesurf, a Rust browser engine for AI agents, whose README says it speaks CDP so that clients such as Puppeteer can connect to it. A tool built for one browser can talk to a very different engine, as long as both implement enough of the protocol.

What CDP is

The protocol is defined in the public ChromeDevTools/devtools-protocol repository, under the BSD-3-Clause licence. The repository holds the definitions in two forms, .pdl and json/, plus TypeScript types, and publishes them as the devtools-protocol npm package. The README says those files are generated daily by a script and must not be edited by hand, and that the repository does not track issues about the protocol's definition or implementation: bugs go to the Chromium tracker. The viewer at chromedevtools.github.io/devtools-protocol offers three versions: Tip-of-Tree (the latest), Stable (1.3) and the V8 Inspector variant used by Node.js.

The protocol is organised into domains, each covering one area of the browser, and each domain has commands (things you ask the browser to do), events (things it tells you about) and types. We counted them in the two JSON files on the repository's main branch on 14 November 2026, version 1.3:

  • browser_protocol.json: 53 domains, 595 commands and 210 events. These include Page, Network, DOM, CSS, Input, Emulation, Target and Accessibility.
  • js_protocol.json: 6 domains, 82 commands and 22 events, including Runtime (JavaScript evaluation) and Debugger.
Size of the Chrome DevTools Protocol definitions (version 1.3)count
Size of the Chrome DevTools Protocol definitions (version 1.3) (count)
count
Browser commands595
Browser events210
JS commands82
JS events22

Source: devtools-protocol repository, browser_protocol.json and js_protocol.json, read 14 November 2026

Not all of it is stable. In the browser protocol, 39 of the 53 domains are marked experimental in the JSON. The README gives no compatibility policy, so a script that leans on an experimental domain should expect to be adjusted when the browser updates. The accessibility tree command Accessibility.getFullAXTree and the DOM snapshot command DOMSnapshot.captureSnapshot are examples: both live in domains marked experimental.

What a conversation looks like

Over a WebSocket, the client sends a command as a JSON message with an id, a method of the form Domain.command, and params. The browser answers with the same id and a result; events arrive as messages with a method and params and no id. An illustrative exchange, using the definitions in the JSON files:

-> {"id": 1, "method": "Page.navigate", "params": {"url": "https://example.com"}}
<- {"id": 1, "result": {"frameId": "...", "loaderId": "..."}}
<- {"method": "Page.frameNavigated", "params": {...}}

In the JSON, Page.navigate takes a required url and optional referrer, transitionType and frameId, and returns frameId, loaderId, errorText and isDownload. Page.captureScreenshot takes an optional format (jpeg, png or webp, png by default), a quality for JPEG, and an optional clip region. Other commands we checked exist as you would expect: Runtime.evaluate, Input.dispatchMouseEvent, Network.getCookies, Page.printToPDF and Emulation.setDeviceMetricsOverride. The Target domain, described as supporting "additional targets discovery", lets a client attach to other targets such as tabs and frames.

How you connect

A Chromium-based browser started with remote debugging serves an HTTP endpoint. Chrome's own remote-debugging guide shows the idea with an Android device forwarded to port 9222: http://localhost:9222/json lists page targets and http://localhost:9222/json/version exposes the browser target endpoint, the WebSocket address a client connects to.

To try it on a desktop, start Chrome with a dedicated profile folder (this matters, see the security section), then ask for the version:

chrome --remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile
curl http://localhost:9222/json/version

You do not have to write the messages yourself. Three common routes:

  • Puppeteer. Its documentation describes it as a JavaScript library with a high-level API for automating a browser, communicating through CDP and WebDriver BiDi. It drives Chrome and Firefox and runs headless by default. Use cases it lists include screenshots and PDFs, form submission, UI testing and crawling single-page applications.
  • Playwright, raw session. Playwright's CDPSession lets you "talk raw" CDP: create one with page.context().newCDPSession(page), send commands with session.send(method, params) and listen to every event with session.on('event'). The documented example enables the Animation domain and changes the playback rate.
  • Playwright, attach to a running browser. browserType.connectOverCDP(endpointURL) attaches to an existing Chromium-based browser, with an address such as http://localhost:9222/. The docs warn that "This connection is significantly lower fidelity than the Playwright protocol connection" and say it supports only Chromium-based browsers; for advanced features they point to browserType.connect() instead.

That last point is the practical lesson for agent builders: the closer a client stays to CDP's raw model, the more it depends on each engine implementing the same commands. An engine that supports a subset will work for screenshots and page text and may fail on the rest. Kitesurf's own README says some Chrome DevTools features do not work yet.

Why agents like it, and what they should be careful about

A few things make CDP a good fit for agents:

  1. One protocol, many clients. Existing automation code, MCP servers and test tools already speak it.
  2. Everything is reachable. Screenshots, PDFs, accessibility data, network traffic and input events are all commands, so an agent can choose a compact text view of a page instead of pixels. The accessibility and DOM snapshot commands are one way to get structure, though they are in experimental domains.
  3. Browser state is a first-class object. The same channel that clicks a button can read cookies or evaluate JavaScript in the page, which is also the source of the risk.

The security side

Remote debugging is a full-control interface. Chrome's developer blog (Will Harris, 17 March 2025) said that since App-Bound Encryption was enabled, Google had seen more attackers use Chrome remote debugging to extract cookies, helped by public tools and blog posts. From Chrome 136, the --remote-debugging-port and --remote-debugging-pipe switches are ignored when they target the default Chrome data directory; they work only together with a --user-data-dir that points at a non-standard directory, which uses a different encryption key. In the post's words, "These switches will no longer be respected if attempting to debug the default Chrome data directory." Google's advice for developers is to use a custom user data directory, and for browser automation to use Chrome for Testing, which keeps the previous behaviour.

That is why the command above uses a throwaway profile folder: it keeps your real logins out of the debugged browser.

The change is a hardening step, not a boundary. On 13 August 2026 SpecterOps published "Return of the Cookie Monster", describing a technique that turns CDP on inside an already running Chrome or Edge process instead of launching it with a flag. The author's tool locates the browser module, resolves internal symbols and starts the browser's remote debugging server on a chosen local port, after which it can dump cookies, list tabs and drive the logged-in session. It requires code execution that can inject into the browser process, a signature set matching the exact browser build, a local TCP port and a logged-in user. The post suggests detecting process injection into browsers with Sysmon events 8 and 10 (a remote thread created in chrome.exe or msedge.exe, and a process access with mask 0x143a). Our reading: CDP access is equivalent to the user's logged-in browser, so the defence is to keep unknown code off the machine and the port closed, not only to change launch flags.

Practical rules for anyone running agents with CDP:

  • Use a dedicated profile with no personal logins; never point an agent at your everyday browser profile.
  • Keep the debugging port on localhost. The examples in Chrome's documentation use localhost; do not expose it to a network. Kitesurf's README warns that the engine has no built-in authentication and says not to deploy it without Cloudflare Access or another authentication layer; the same thinking applies to any CDP endpoint.
  • Treat page content as untrusted input to the agent, because the agent's browser can click and read on your behalf.
  • Pin and test your client against the browser version you run; experimental domains change.

Quick reference

Task Where to look
Browse commands and events the protocol viewer, Tip-of-Tree for the latest
Types for TypeScript the devtools-protocol npm package
Raw access from Playwright page.context().newCDPSession(page)
Attach Playwright to a running Chromium browserType.connectOverCDP('http://localhost:9222/')
Debug safely in Chrome 136 and later --remote-debugging-port plus a non-default --user-data-dir

What we could not confirm

We did not find a stability policy for the protocol in the repository README, so how long an experimental command stays unchanged is unknown. We have not benchmarked any engine's CDP coverage, so we cannot say how much of the protocol a given agent browser implements; check its documentation and test suite before relying on it.

Sources

Written by

audiotale.net team

The official account of the people who run audiotale.net: announcements, conversation starters and the newsroom's drafts. Posts written with AI say so. Every other account here is a real person.