ScreenshotNeo

BlogHow-to

How to Use CDPSession in Puppeteer

Create a Puppeteer CDP session, send Chrome DevTools Protocol commands, listen for events, and clean up safely—with runnable examples and troubleshooting.

By the ScreenshotNeo team4 October 20266 min read

CDPSession is Puppeteer’s interface for sending raw Chrome DevTools Protocol (CDP) commands to a browser target and listening for protocol events. For a page, create one with await page.createCDPSession(), send commands with session.send(method, params), subscribe with session.on(event, handler), and call session.detach() when finished. Puppeteer describes these sessions as a way to talk to the raw Chrome DevTools Protocol (CDPSession API reference).

Use a CDP session when Puppeteer’s higher-level Page and Browser APIs do not expose the protocol feature you need. The examples below use JavaScript and Puppeteer’s documented page-scoped creation method.

1. Create a page CDP session

Start with a page created by Puppeteer, then ask that page for a CDP session. The session is attached to that page; it is not a session constructor you should instantiate yourself. The constructor is internal to Puppeteer.

const client = await page.createCDPSession();

Page.createCDPSession() returns a Promise<CDPSession> attached to the page (Page.createCDPSession() reference). Keep the session handle for as long as you need to send commands or receive events.

2. Send commands and listen for events

A CDP command is identified by a method string such as Animation.enable. Pass its parameters as the second argument when the command needs them. Await the returned promise when you need the command result or need to know the command has completed. Register an event handler with on to receive protocol events.

const client = await page.createCDPSession();

await client.send('Animation.enable');
client.on('Animation.animationCreated', () => {
  console.log('Animation created!');
});

const response = await client.send('Animation.getPlaybackRate');
await client.send('Animation.setPlaybackRate', {
  playbackRate: response.playbackRate / 2,
});

This follows Puppeteer’s documented Animation example: enable the domain, subscribe to Animation.animationCreated, read the playback rate, and set it to half its prior value (CDPSession API reference). A protocol domain may require setup before its commands or events are available; check the documentation for the particular CDP domain and command you use instead of assuming every domain has identical setup.

How send() is typed

Puppeteer’s send() method is mapped to its protocol command definitions: the selected command determines the accepted parameter shape and result type in typed code. Both the parameters and command options are optional in the API signature; consult the command’s protocol definition for its actual requirements (CDPSession.send() reference).

3. Clean up the session

Detach when the code no longer needs this session. After detaching, it emits no further events and cannot send more messages (CDPSession.detach() reference).

const client = await page.createCDPSession();
try {
  await client.send('Animation.enable');
  // Use the session while it is needed.
} finally {
  await client.detach();
}

The finally block makes cleanup run if the command or work inside the block throws. If event handlers are part of a longer-lived workflow, keep the session attached for that workflow and detach it at the actual end of use.

4. Complete runnable example

This standalone Node.js script launches Chromium with Puppeteer, opens a page, creates a session, listens for an Animation event, sends the documented playback-rate commands, and closes resources. Save it as cdp-session.js, install Puppeteer with npm install puppeteer, then run node cdp-session.js. The example demonstrates the documented protocol pattern; it does not assume that a particular page will create an animation during navigation.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  let client;

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

    client = await page.createCDPSession();
    await client.send('Animation.enable');

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

    const response = await client.send('Animation.getPlaybackRate');
    console.log('Current playback rate:', response.playbackRate);

    await client.send('Animation.setPlaybackRate', {
      playbackRate: response.playbackRate / 2,
    });
    console.log('Set playback rate to half the reported value.');
  } finally {
    if (client) {
      await client.detach();
    }
    await browser.close();
  }
})().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

5. Choose the right attachment scope

Method Attachment When to use it
page.createCDPSession() The page Use for page-level protocol work. This is the recommended route shown in this guide.
target.createCDPSession() A target Use when your code already has the relevant target and needs a session attached to it. Puppeteer describes targets as debuggable entities such as frames, pages, or workers; check the API documentation for the target behavior you need.

Puppeteer marks Page.target() obsolete and directs page-session creation to Page.createCDPSession(). Do not use page.target().createCDPSession() as the current page-scoped pattern (Page.target() reference, Target.createCDPSession() reference).

6. Common errors and fixes

Symptom Likely cause Fix
page.createCDPSession is not a function The value is not a Puppeteer Page, or the installed Puppeteer version/API differs from the documentation. Confirm that the object came from browser.newPage() or another Puppeteer page-producing method, and check the API reference matching your installed package.
A send fails after cleanup The session was detached. Detached sessions cannot send messages. Create a new page session when needed, and keep it attached for the full period of use.
The command rejects with a protocol error The method name, parameters, target state, or domain setup may not match the protocol command’s requirements. Check the command and parameter schema for the relevant Chrome DevTools Protocol domain, ensure any required domain setup has happened, and inspect the rejection details.
No event arrives The event may not have occurred, the relevant domain may not be enabled, or the listener may have been registered too late. Register the listener before the action expected to trigger it. Enable the domain if its documentation requires that step, then verify the page actually triggers the event.
A protocol call times out The individual protocol call exceeded its configured timeout. Puppeteer’s ConnectOptions.protocolTimeout controls the timeout for individual protocol calls; its documented default is 180,000 ms in API version 25.12.0. Set it in the browser launch/connect options when appropriate; it is not a per-send() parameter (ConnectOptions reference).

7. Reliability, performance, and cost

CDP calls are asynchronous. Await commands whose results or ordering matter, and handle rejected promises so protocol errors do not become unhandled failures. Keep event callbacks short; if a callback starts asynchronous work, handle errors from that work explicitly. Detach at the end of a bounded task to stop event delivery and prevent later accidental sends.

Each send() is a browser protocol operation with asynchronous completion. Avoid issuing commands in a tight loop when one result can be reused, and avoid waiting for events that the page may never emit without an application-level timeout or cancellation plan. The cited API references provide no general CDPSession performance benchmark, so actual latency depends on the command and browser workload.

Puppeteer and CDP are software APIs rather than a per-screenshot hosted service, so these references establish no per-command service price. Your own operating costs depend on where Chromium runs and how you provision it. If the goal is simply to obtain screenshots rather than control arbitrary browser protocol behavior, ScreenshotNeo offers a hosted screenshot API with one GET request and a free allowance of 1,000 shots per month.

8. Or skip the browser setup

For a screenshot rather than custom CDP control, use ScreenshotNeo. Its API accepts a URL and returns PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API docs for 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 accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots monthly with no card; paid plans start at $5 for 3,000 screenshots.

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

FAQ

Can I construct a CDPSession directly?

No. Puppeteer documents the constructor as internal. Create sessions through the page or target APIs.

Does every CDP command need a parameter object?

No. The send() signature makes parameters optional, but an individual protocol command can define required parameters.

Can I use a session after detaching?

No. Detaching ends event emission and prevents further sends through that session.

Which Puppeteer version do these references cover?

The CDPSession, page creation, send, detach, and ConnectOptions references cite version 25.12.0. The Target creation reference available for this guide identifies version 25.10.0, so check your installed-version documentation for version-specific details.