Skip to main content
Access Chrome DevTools Protocol directly for advanced browser control beyond Playwright’s API.

Getting a CDP Session

getCDPSessionForPage

Returns a CDP session for a page by reusing Playwright’s internal WebSocket connection.
import { getCDPSessionForPage } from 'playwriter'
import type { ICDPSession } from 'playwriter'

const cdp: ICDPSession = await getCDPSessionForPage({ page })

// Send CDP commands
const metrics = await cdp.send('Performance.getMetrics')

// Listen to CDP events
cdp.on('Network.requestWillBeSent', (params) => {
  console.log('Request:', params.request.url)
})
Parameters:
page
Page
required
Playwright Page instance
Returns: Promise<PlaywrightCDPSessionAdapter>
This function reuses Playwright’s internal CDP session instead of creating a new one, which is required for the relay server.

ICDPSession Interface

Type-safe CDP session interface with full autocomplete support.
export interface ICDPSession {
  send<K extends keyof ProtocolMapping.Commands>(
    method: K,
    params?: ProtocolMapping.Commands[K]['paramsType'][0],
    sessionId?: string | null,
  ): Promise<ProtocolMapping.Commands[K]['returnType']>

  on<K extends keyof ProtocolMapping.Events>(
    event: K,
    callback: (params: ProtocolMapping.Events[K][0]) => void,
  ): unknown

  off<K extends keyof ProtocolMapping.Events>(
    event: K,
    callback: (params: ProtocolMapping.Events[K][0]) => void,
  ): unknown

  detach(): Promise<void>
  getSessionId?(): string | null
}
Return types are automatically inferred from the command string. For example:
  • cdp.send('Page.getLayoutMetrics') returns Promise<Protocol.Page.GetLayoutMetricsResponse>
  • cdp.send('Runtime.evaluate', { expression: '1+1' }) returns Promise<Protocol.Runtime.EvaluateResponse>

PlaywrightCDPSessionAdapter

Wraps Playwright’s CDPSession to implement the ICDPSession interface.
import { PlaywrightCDPSessionAdapter } from 'playwriter'
import type { CDPSession as PlaywrightCDPSession } from '@xmorse/playwright-core'

const context = page.context()
const playwrightSession: PlaywrightCDPSession = await context.getExistingCDPSession(page)
const cdp = new PlaywrightCDPSessionAdapter(playwrightSession)

// Now use the type-safe interface
await cdp.send('Page.setDeviceMetricsOverride', {
  width: 375,
  height: 812,
  deviceScaleFactor: 3,
  mobile: true,
})

CDP Commands Examples

Performance Metrics

const cdp = await getCDPSessionForPage({ page })

const metrics = await cdp.send('Performance.getMetrics')
console.log(metrics.metrics.find(m => m.name === 'JSHeapUsedSize'))

Network Monitoring

const cdp = await getCDPSessionForPage({ page })

await cdp.send('Network.enable')

cdp.on('Network.requestWillBeSent', (params) => {
  console.log('Request:', params.request.url)
})

cdp.on('Network.responseReceived', (params) => {
  console.log('Response:', params.response.status, params.response.url)
})

Console Messages

const cdp = await getCDPSessionForPage({ page })

await cdp.send('Runtime.enable')

cdp.on('Runtime.consoleAPICalled', (params) => {
  console.log('Console:', params.type, params.args)
})

JavaScript Coverage

const cdp = await getCDPSessionForPage({ page })

// Start coverage
await cdp.send('Profiler.enable')
await cdp.send('Profiler.startPreciseCoverage', {
  callCount: true,
  detailed: true,
})

// Navigate and interact with page
await page.goto('https://example.com')

// Get coverage data
const coverage = await cdp.send('Profiler.takePreciseCoverage')
console.log('Functions executed:', coverage.result.length)

Emulation

const cdp = await getCDPSessionForPage({ page })

// Emulate timezone
await cdp.send('Emulation.setTimezoneOverride', {
  timezoneId: 'America/New_York',
})

// Emulate geolocation
await cdp.send('Emulation.setGeolocationOverride', {
  latitude: 40.7128,
  longitude: -74.0060,
  accuracy: 100,
})

Detaching

Detach the CDP session when done:
await cdp.detach()
Detaching closes the CDP connection. Don’t detach if you’re using Playwright’s built-in CDP session.

Build docs developers (and LLMs) love