PuppeteerClient

PuppeteerCommunicator - The CDP Transport Layer

PuppeteerCommunicator owns the websocket (or pipe) connection to the browser's DevTools endpoint, tracks frame/context/session IDs, queues CDP events, and matches asynchronous CDP responses back to the calls that requested them. browser.PuppeteerCommunicator exposes this connection on a live Browser instance using a Puppeteer-based engine (PuppeteerPort, PuppeteerPortHW, PuppeteerPipe, PuppeteerPipeHW). PuppeteerClient is built on top of PuppeteerCommunicator - every PuppeteerClient endpoint ultimately becomes one or more raw CDP commands sent through PuppeteerCommunicator and resolved against its response/event queues. Like PuppeteerClient, this is a completely custom CDP implementation written for GPAL - not derived from, or dependent on, the Node.js Puppeteer library or any third-party .NET Puppeteer package. WithPuppeteerCommunicator hands a client an existing communicator rather than letting it open its own.

NOTE

Most workflows never touch PuppeteerCommunicator directly - PuppeteerClient and the Browser fluent API cover the vast majority of CDP operations. Reach for PuppeteerCommunicator only when you need a CDP domain/method that has no PuppeteerClient endpoint yet, or when building new PuppeteerClient endpoint mappings.

WARNING

PuppeteerCommunicator is the transport layer. It speaks raw CDP, so use it to make the CDP calls GPAL has no fluent call for: the DevToolsMethods enum carries the complete set of CDP commands, so anything the protocol supports can be sent from here to supplement what GPAL already does.

Examples

GPAL Fluent: High-level fluent C# API

//Every method is async and takes a session id last. Passing null uses the session the browser is on, which is what a workflow wants unless it is driving a specific tab, window or iframe it got the id for itself. GetAwaiter().GetResult() is how a synchronous GPAL workflow calls them; an async workflow awaits instead. SendCommand is the general case: the DevTools method, that method's parameters as an anonymous object, and the session. The parameter names are the CDP protocol's own, so width, height, deviceScaleFactor and mobile are what Emulation.setDeviceMetricsOverride documents, not names GPAL invented. It answers the raw CDP result, so read it the way the protocol describes it rather than expecting a GPAL shape. Calls differ in what they identify an element by. Some take a css selector, as GetCssAttributes does. Others take a backend node id, which is CDP's own handle for a node and is what a GPALElement carries, so those are for code that already has an element rather than for finding one.

// every call takes a session id last, and null means the session the browser is on now

IBrowser browser = GPAL.Browser

.WithAutomationEngine(AutomationEngine.PuppeteerPort)

.GoTo("https://example.com")

.ToGPALObject();


PuppeteerCommunicator cdp = browser.PuppeteerCommunicator;


// 1. a method with its own parameters: a css selector and the session

int nodeId = cdp.QueryByCss("#main a.download", null).GetAwaiter().GetResult();

dynamic styles = cdp.GetCssAttributes(nodeId, null).GetAwaiter().GetResult();

dynamic answer = cdp.ExecuteJavaScript("document.title", null).GetAwaiter().GetResult();


// 2. optional parameters, named so the defaults in between are left alone. CheckNetworkIdle waits for

// the page to stop talking rather than for a fixed time

bool settled = cdp.CheckNetworkIdle(sessionId: null, maxConnections: 0, timeoutMs: 15000)

.GetAwaiter().GetResult();


// 3. a raw CDP command for a domain GPAL has no call for. SendCommand takes the method, an anonymous

// object of that method's own parameters, and the session

dynamic metrics = cdp.SendCommand(DevToolsMethods.PerformanceGetMetrics, new { }, null)

.GetAwaiter().GetResult();


dynamic emulated = cdp.SendCommand(DevToolsMethods.EmulationSetDeviceMetricsOverride,

new { width = 1280, height = 800, deviceScaleFactor = 2, mobile = false }, null)

.GetAwaiter().GetResult();

💬 Ask GPAL