How Chromium's Protocol Monitor Exposes Raw CDP Messages
This article provides a technical overview of how the Protocol Monitor in the Chromium web browser intercepts, processes, and displays raw JSON-RPC 2.0 messages transmitted over the Chrome DevTools Protocol (CDP). By examining the DevTools frontend architecture, internal message routing hooks, and UI rendering pipelines, you will understand how browser instrumentation traffic is exposed in real-time for debugging and development.
The DevTools Frontend Architecture
Chrome DevTools is a web application written in TypeScript that runs in its own renderer process. To inspect and debug a web page, the DevTools frontend communicates with the Chromium browser backend and its various processes using the Chrome DevTools Protocol (CDP).
Every action taken in the DevTools UI—such as inspecting a DOM node, pausing on a JavaScript breakpoint, or recording network activity—is translated into a raw JSON-RPC 2.0 message. The Protocol Monitor is a built-in experimental panel within DevTools designed to tap directly into this communication channel and reveal these underlying payloads.
Message Interception via InspectorBackend
The core mechanism that exposes raw CDP messages lies within the
protocol_client module of the DevTools frontend source
code. All CDP traffic is routed through a central management class known
as InspectorBackend.
Rather than parsing traffic at the network socket level, the Protocol
Monitor hooks directly into the InspectorBackend message
dispatcher. When the Protocol Monitor panel is opened by the user, it
registers callback functions onto internal instrumentation hooks:
onMessageSent and onMessageReceived. Because
these hooks sit at the boundary between the DevTools application logic
and the transport layer, they have access to the exact JSON payloads
moving in both directions.
Capturing Outgoing Requests
When a DevTools panel requests data from the browser, it invokes a CDP command. The frontend serializes this command into a JSON-RPC request object containing three primary properties:
id: A sequentially generated integer used to track the request.method: The CDP domain and command name (e.g.,Page.navigateorDOM.getDocument).params: An object containing the arguments required by the method.
Right before this serialized JSON string is passed to the underlying
transport layer (which is either a WebSocket connection for remote
debugging or Chromium's internal InspectorFrontendHost C++
bindings for local debugging), the onMessageSent hook
fires. It passes a clone of the raw JSON object and the target metadata
directly to the Protocol Monitor controller, which logs the outgoing
request immediately.
Capturing Incoming Responses and Events
Traffic flowing from the Chromium backend to the DevTools frontend
consists of two types of JSON-RPC messages: command responses and
asynchronous events. When the transport layer receives a raw JSON string
from the browser, it parses the string into a JavaScript object and
immediately triggers the onMessageReceived hook before
routing the data to the rest of the DevTools UI.
The Protocol Monitor inspects the incoming object to determine its type:
- Responses: If the JSON object contains an
idproperty, the Protocol Monitor identifies it as a response to a previously sent command. It extracts theresultobject (or theerrorobject if the command failed) and pairs it with the matching outgoing requestid. This pairing allows the monitor to calculate the exact round-trip execution time in milliseconds. - Events: If the JSON object lacks an
idbut contains amethodandparams, it is classified as an asynchronous event (e.g.,Network.requestWillBeSent). The Protocol Monitor logs this as a standalone incoming message.
Handling Multiplexed Sessions
Modern Chromium architecture uses a flat session hierarchy to debug
multiple targets—such as iframes, web workers, and service workers—over
a single shared connection. To route messages to the correct target, CDP
appends a sessionId field to the root of the JSON-RPC
payload.
The Protocol Monitor extracts this sessionId directly
from the raw message and cross-references it with the active Target
Manager in DevTools. This allows the monitor to expose not just the raw
JSON payload, but also the specific execution context or target that
generated or received the message.
Rendering and Injecting Raw Payloads
Once the ProtocolMonitor module intercepts the raw
objects, it appends them to an internal array and renders them inside a
virtualized data grid. To ensure performance does not degrade during
heavy browser activity, the UI only renders the text for visible
rows.
When a user selects a specific message in the grid, the Protocol
Monitor passes the unmutated JavaScript object representation of the
JSON-RPC payload into a read-only object tree viewer. Furthermore, the
Protocol Monitor exposes a command input bar at the bottom of the panel.
When a developer types a raw JSON string into this input, the monitor
bypasses the standard DevTools UI modules and injects the payload
directly into the MainConnection.sendRawMessage method,
sending the custom JSON-RPC command straight to the Chromium
backend.