ScreenshotNeo

BlogHow-to

How to Send Chrome DevTools Protocol Commands with Puppeteer

Use Puppeteer’s CDP session to send Chrome DevTools Protocol commands, read results, and handle events. Includes lifecycle, compatibility, and troubleshooting guidance.

By the ScreenshotNeo team4 October 20268 min read

Use page.createCDPSession() to open a Chrome DevTools Protocol (CDP) session for a Puppeteer page, then call client.send('Domain.command', params). The returned promise resolves to the protocol response. Subscribe to protocol events with client.on(), and detach the session when you are done.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.goto('https://example.com');

  const client = await page.createCDPSession();
  try {
    await client.send('Animation.enable');
    client.on('Animation.animationCreated', event => {
      console.log('Animation created:', event);
    });

    const { playbackRate } = await client.send('Animation.getPlaybackRate');
    console.log('Playback rate:', playbackRate);

    await client.send('Animation.setPlaybackRate', {
      playbackRate: playbackRate / 2,
    });
  } finally {
    await client.detach();
  }
} finally {
  await browser.close();
}

Save this as an ES module (for example, cdp-demo.mjs) in a project with Puppeteer installed, then run it with Node.js. The example uses the Animation domain: it enables the domain, registers an event listener, reads the playback rate, and sends a command with a parameter. The browser and session are both closed even if a command fails.

1. What a CDP session does

Puppeteer provides higher-level APIs for common browser tasks. A CDP session gives you a lower-level channel to send Chrome DevTools Protocol commands when you need a capability that is not exposed by the higher-level Page or Browser API. CDP organizes commands and events into domains such as Page, Network, Runtime, and Animation. [Puppeteer CDPSession API] [Puppeteer guides]

A command name is a string in the form Domain.command. Pass a parameter object if that command accepts parameters. The result is a promise resolving to the protocol response object, whose properties depend on the method. Commands and events are browser-protocol features: confirm that the method exists in the browser version and Puppeteer protocol mapping you use.

2. Create a page-attached session

For commands operating on a page, create the page as usual and call await page.createCDPSession():

const page = await browser.newPage();
await page.goto('https://example.com');
const client = await page.createCDPSession();

Page.createCDPSession() returns a CDPSession attached to that page. Prefer it over page.target() for obtaining a page session; Puppeteer marks Page.target() obsolete and directs users to create the session from the page. [Page.createCDPSession API] [Page.target API]

3. Send commands and read their results

Call send() with a method name and, when required, a parameter object. Await the result so errors can be handled and the response is available before later steps run.

const result = await client.send('Animation.getPlaybackRate');
console.log(result.playbackRate);

await client.send('Animation.setPlaybackRate', {
  playbackRate: result.playbackRate / 2,
});

Some methods require parameters; others do not. Use the command’s protocol definition as the authority for required fields and result shape. For commands represented in the installed Puppeteer protocol mapping, TypeScript can provide command and parameter type checking. It cannot make a command supported by a browser that does not implement it.

4. Listen for protocol events

Register a listener on the session with the event name from the relevant domain. Enable the domain first when its protocol documentation requires it:

await client.send('Animation.enable');

const onAnimationCreated = event => {
  console.log('Animation created:', event);
};
client.on('Animation.animationCreated', onAnimationCreated);

// Later, if you no longer need this handler:
client.off('Animation.animationCreated', onAnimationCreated);

Events arrive asynchronously, so a listener should be registered before the action that is expected to produce the event. Remove listeners when they are no longer needed, especially in long-lived processes that create repeated pages or sessions. A detached session cannot send commands or emit events. [CDPSession API]

5. Attach to a different target when needed

Use a page-created session for page work. Puppeteer also documents target.createCDPSession() for attaching to a CDP target. Targets can represent pages, frames, or workers, so target-level attachment is useful when the context you need is not the page API’s context. [Target.createCDPSession API]

// When you already have the relevant Puppeteer Target:
const client = await target.createCDPSession();
try {
  const result = await client.send('Runtime.evaluate', {
    expression: 'location.href',
  });
  console.log(result);
} finally {
  await client.detach();
}

Check the command’s target requirements before attaching. A command valid for one target type may not apply to another, and commands that act on a page should generally use a page session.

6. Manage session and browser lifecycle

Keep the session attached while commands and event handlers are in use, then call await client.detach(). Detachment ends that session’s ability to send messages and receive events; create a new session if you need to use CDP again. Put cleanup in a finally block so it runs when a command rejects.

Close the browser when the script owns it. If the script connects to a browser owned by another process, follow that browser’s ownership and disconnect lifecycle instead of closing a browser you do not own. The basic launch-and-close example above illustrates the owned-browser case.

7. Compatibility and protocol versions

Puppeteer releases are paired with particular browser releases to preserve protocol compatibility. Puppeteer uses CDP by default for Chrome automation and also supports WebDriver BiDi. The CDP tip-of-tree reference changes frequently and can contain methods that are experimental or incompatible with older browser builds. The stable 1.3 protocol is a smaller subset tagged at Chrome 64. [Puppeteer FAQ] [Chrome DevTools Protocol reference]

  • Check the protocol documentation and command availability for the browser you actually run.
  • Keep Puppeteer and its paired browser version aligned where possible.
  • Do not assume a command from the tip-of-tree reference exists in every installed browser.
  • Use Puppeteer’s higher-level API when it already supports the operation; raw CDP can tie code to Chrome protocol details.
  • If cross-browser portability matters, evaluate WebDriver BiDi and its feature support rather than assuming CDP behavior transfers.

8. Options and configuration that matter

Choice Use it for Things to check
Session scope Page work or a non-page target such as a worker Use page.createCDPSession() for page work; target attachment for another target.
Command method A protocol operation in a domain Exact method spelling, required parameter fields, target support, and browser support.
Event subscription Asynchronous notifications from a domain Enable the domain if required; register before the triggering action; remove listeners when done.
Session timeout Bound how long an individual protocol call may wait Puppeteer 25.12.0 documents a default protocolTimeout of 180,000 ms in ConnectOptions. This is version-sensitive; verify the installed release’s API reference before configuring it. [ConnectOptions API]

The protocol timeout is not a substitute for navigation or application-level timeouts. Configure the relevant timeout for the operation you are waiting on, and handle a rejected command explicitly.

9. Troubleshooting common errors

Symptom Likely cause Fix
Protocol error: ... method wasn't found or a similar unknown-method response The browser does not implement that method, or the installed Puppeteer and browser protocol versions do not match the docs you consulted. Check the browser version, use its matching protocol reference, and select a supported command or browser version.
Command rejects with invalid parameters A required field is missing, misspelled, or has the wrong shape or value. Compare the parameter object with the command definition for the installed protocol version. Await and catch send() failures.
Session cannot send after detach The session was detached, or its target/browser closed. Create a new session from a live page or target; do not reuse a detached session.
No event arrives The relevant domain was not enabled, the listener was added after the event, the event condition did not occur, or the session target is wrong. Enable the domain where required, register the listener first, trigger the relevant action, and confirm the target scope.
Call times out The command or browser did not respond within the configured protocol timeout. Check browser health and command support, then set a suitable timeout for the installed Puppeteer version. Avoid increasing timeouts without identifying why the operation is waiting.
TypeScript rejects a method or parameter The installed Puppeteer protocol mapping may not include that method or may define a different parameter shape. Confirm the package version and protocol support. If using a newer browser feature, update to a compatible Puppeteer release or use a supported command.

10. Performance, reliability, and cost

CDP adds a protocol round trip for each command, so avoid unnecessary serial calls when a higher-level Puppeteer method can perform the task. Keep event listeners scoped and remove them to prevent stale handlers in long-running automation. Reuse a live browser and page where that fits the workload, but create and detach sessions according to the target and task lifecycle.

Reliability depends on the browser process, target lifecycle, command support, and protocol version pairing. Treat protocol errors and timeouts as normal failure paths: await calls, catch errors at an appropriate boundary, and clean up sessions. The research sources provide no general CDP performance benchmark or fixed monetary cost; infrastructure and browser runtime costs depend on how and where you run the browser.

11. When a screenshot is the actual goal

If you need direct browser control, Puppeteer and CDP give you code-level access to commands and events. If the task is simply to capture a website as an image or PDF, a screenshot API can avoid maintaining browser setup. ScreenshotNeo is a website screenshot API and MCP server for developers.

12. Or skip the browser setup

For a website screenshot, call the API with the URL and your access key. See the ScreenshotNeo API documentation for the available formats and options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is available on every plan.

Sign up free for 1,000 screenshots a month, with no card required.

13. FAQ

Can I send any Chrome DevTools Protocol method through Puppeteer?

You can send methods exposed by the browser’s CDP endpoint, but availability depends on the browser build and target. Check support for the exact browser and Puppeteer versions you run.

Does a CDP session replace Puppeteer’s Page API?

No. It is a lower-level option for protocol operations. Prefer the Page or Browser API when it already offers the operation you need.

Can the session be used after detaching?

No. Detaching ends the session’s ability to send commands and emit events. Create a new session from a live target.

Is CDP the right choice for cross-browser automation?

CDP is Chrome-specific in this context. Puppeteer also supports WebDriver BiDi; check the feature coverage and differences for your supported browsers before choosing a protocol.