cdpfleet Pre-launch Get early access

cdpfleet / CDP & Puppeteer

Chrome DevTools Protocol

Puppeteer, raw CDP, remote browsers.

Add "cdp": true to a launch and the response carries a cdpUrl next to wsUrl: a browser-level DevTools WebSocket for Puppeteer, Playwright's connectOverCDP in any version, or your own CDP client. The proxy, timeouts, threads and billing are the same as any other session.

  • 6browsers with a cdpUrl
  • anyPuppeteer or Playwright version
  • 0browsers to install locally

Which browsers, and how to connect

  • cdp: true works on Chrome, Edge, Brave, Opera, Yandex and Chromium. Patchright, Rebrowser, Camoufox, Firefox and WebKit speak Playwright's own protocol only.
  • Puppeteer: puppeteer.connect({ browserWSEndpoint: cdpUrl, headers: { "x-api-key": KEY } }) with puppeteer-core — the browser runs on cdpfleet, nothing to download.
  • Playwright connectOverCDP doesn't need a client of the server's exact version, unlike connect(). You get the Chromium-level API (CDP & Puppeteer).
  • One URL that launches and connects: a Connect URL works for Playwright, Playwright Test and CDP clients that can only take a WebSocket address.
  • Recordings: a headless session is recorded when it has cdp or live_view (headless-recording recipe).
import puppeteer from 'puppeteer-core';
const KEY = process.env.CDPFLEET_API_KEY;
const res = await fetch('https://starter.cdpfleet.com/chrome/session', {
  method: 'POST',
  headers: { 'x-api-key': KEY, 'content-type': 'application/json' },
  body: JSON.stringify({ headless: 'new', cdp: true }),
});
const { cdpUrl } = await res.json();
const browser = await puppeteer.connect({ browserWSEndpoint: cdpUrl, headers: { 'x-api-key': KEY } });
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close(); // ends the session

What CDP adds

  • Core Web Vitals in lab runs: LCP, CLS and TTFB come back from one evaluate with buffered observers, from all five languages; through a proxy, TTFB includes reaching the server via the proxy (case 55).
  • A slow phone on a fast server: one newCDPSession call reaches DevTools' CPU throttling — the same workload ran 2.7–4.0× slower at 4× and 4.1–7.3× slower at 6× (case 56). No cdp: true needed for that: Playwright's newCDPSession works over the normal connection.
  • The cookie jar, read and edited: filter by URL, change a value or expiry, delete one cookie, and carry a login to another session as about 150 bytes of JSON (case 57).
  • Block telemetry, keep the page: news front pages sent dozens of analytics requests per load and kept reporting after the scraper left; blocking them changed no titles or headings (case 59).

What a page can tell

  • The classic CDP tell is gone: the Error.stack getter trick fired in none of six setups — not over CDP, not with Playwright's protocol (case 43).
  • What remains is the browser, not the client: the Error.message getter fires on every Chromium build, whether or not anything is listening, and logging a large object costs measurably more while a client receives the console (case 43).
  • Headless itself is the bigger signal on real protected sites: what gets through where and what a page can read about your browser.