ScreenshotNeo

BlogHow-to

How to Get a Connection from a Puppeteer CDPSession

Use Puppeteer’s documented `CDPSession.connection()` method to access the underlying connection, and handle its optional return value safely.

By the ScreenshotNeo team4 October 20265 min read

Call the documented connection() method on the CDPSession. It returns the underlying Connection when one exists, so its return type is Connection | undefined and your code should check for undefined.

const connection = client.connection();
if (!connection) {
  throw new Error('This CDPSession has no underlying connection');
}

If you are starting with a Puppeteer page, create a page-attached session first with await page.createCDPSession(). See the CDPSession connection() API reference and the Page.createCDPSession() reference.

Get the connection from a page session

This TypeScript example launches Chromium, opens a page, creates a CDP session, obtains the connection, and closes the browser. Install Puppeteer with npm install puppeteer, then save this as connection.ts and run it using your project’s TypeScript runner or compile it with TypeScript.

import puppeteer from 'puppeteer';

async function main(): Promise<void> {
  const browser = await puppeteer.launch();

  try {
    const page = await browser.newPage();
    const client = await page.createCDPSession();
    const connection = client.connection();

    if (!connection) {
      throw new Error('This CDPSession has no underlying connection');
    }

    console.log('Underlying connection is available');

    // Use the session for protocol commands and events, for example:
    const version = await client.send('Browser.getVersion');
    console.log(version.product);

    await client.detach();
  } finally {
    await browser.close();
  }
}

main().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

The accessor gives you the connection object; it does not create a session or open a browser. The page’s session is the object you normally use to issue CDP commands with send() and subscribe to protocol events with on().

Handle the optional connection

The method reference documents the return as Connection | undefined, describing it as the underlying connection “if any.” Treat the missing case explicitly rather than assuming all sessions have a connection.

const connection = client.connection();

if (connection === undefined) {
  // Decide what makes sense for your application:
  // throw, skip connection-specific work, or report an unavailable session.
} else {
  // Connection-specific work can proceed here.
}

Use optional chaining only when silently skipping the operation is actually correct for your program. If the connection is required, fail clearly so the issue is not mistaken for a successful operation.

Using the accessor in JavaScript

The same public method is available in JavaScript; the type annotation is unnecessary. For example, in an existing Puppeteer script:

const client = await page.createCDPSession();
const connection = client.connection();

if (!connection) {
  throw new Error('This CDPSession has no underlying connection');
}

console.log('Connection available');

The method name is connection(), including parentheses. It is not a field to read as client.connection.

What the connection accessor does

A CDPSession is Puppeteer’s interface for communicating with the raw Chrome DevTools Protocol. Its documented interface includes sending protocol commands and listening for protocol events. The connection accessor returns the underlying connection if one exists; it does not replace the session’s protocol methods.

Puppeteer’s implementation also defines Connection.fromSession(session), which delegates to session.connection(). For application code, calling the documented accessor directly avoids relying on private fields. The CDPSession constructor is marked internal, so obtain sessions through Puppeteer APIs such as page.createCDPSession() rather than constructing or subclassing them yourself.

Although the accessor itself is documented, do not assume that undocumented internals or every behavior of the returned connection are stable. If your code needs implementation details beyond documented public methods, check the source and API reference for the precise Puppeteer version installed in your project.

Common errors and fixes

Problem Cause Fix
client.connection is not a function The value is not the expected Puppeteer CDPSession, or code is reading an incompatible object. Confirm that client came from await page.createCDPSession() or another Puppeteer API that returns a CDPSession. Call client.connection().
Cannot read properties of undefined The code assumes a connection is always present. Check the result of connection() before using it, and decide how your app should handle the absent case.
Cannot find name Connection or a type import fails The code references the type without importing it, or the installed Puppeteer version’s exports differ. For simple access, let TypeScript infer the return type. If you need an explicit type, consult the API reference and exports for your installed version.
Protocol command fails after getting the connection Obtaining the connection does not ensure a particular protocol command is valid in the current browser or session context. Use the CDPSession’s documented send() interface for protocol commands, check the command and parameters against the relevant protocol version, and handle its rejection.
Code relies on a private connection field An internal implementation detail was mistaken for public API. Use the documented connection() accessor. Verify any additional internal dependency against the exact Puppeteer version in use.

Performance and reliability notes

  • Creating a session is separate work. page.createCDPSession() is asynchronous and returns a promise. Call it when you need a page-attached protocol session; the accessor itself retrieves the session’s connection.
  • Handle lifecycle and errors. Keep the browser and session available while performing protocol work, handle rejected asynchronous commands, and detach the session or close the browser when finished.
  • Keep version-sensitive assumptions narrow. The documented method and optional return type are the safe basis. Check the documentation matching your installed Puppeteer version if you depend on other connection behavior.
  • No performance benchmark is implied. The API documentation establishes the accessor and its return type, not timing or throughput guarantees.

Or skip the browser setup

If your goal is to capture a website rather than work directly with CDP, ScreenshotNeo provides a screenshot API and MCP server for developers. One GET request returns an image or PDF; the API documentation covers its 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);
  • Cookie banners are accepted like a visitor, and known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. Response headers report the page verdict and billing status.
  • An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
  • 1,000 screenshots a month are free with no card. Paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

FAQ

Does every CDPSession have a connection?

The documented return type is optional, so handle the possibility that connection() returns undefined.

Should I access a private connection property instead?

No. Use the public connection() method. Private implementation details can vary by Puppeteer version.

Do I need the connection to send CDP commands?

For commands and events, the CDPSession itself provides send() and event handling. Obtain the connection when your code specifically needs the underlying connection.