CDP mode lets you control the browser through the Chrome DevTools Protocol (CDP). It is useful when WebDriver is too high-level, when a site detects WebDriver traffic, or when you need to manipulate network behavior, cache, cookies, or headers.
This page explains how to enable CDP mode, use the CDP helpers on BaseCase,
send raw CDP commands, and intercept network requests.
“CDP mode” means two things in these docs. Here it is DriverMode::Cdp: a
BaseCase WebDriver session with a DevTools connection next to it. Python
SeleniumBase’s CDP Mode (sb.cdp), which drives Chrome with no driver, is the
pure CDP engine in this crate; the
Python parity table maps its methods there. See
The DevTools Protocol for both.
What you will learn
- How to enable CDP mode in
BrowserConfig. - Which CDP helpers are available on
BaseCase. - How to send raw CDP commands with and without parameters.
- How to use the
CdpReactorto mutate request headers.
Enable CDP mode#
Set the driver mode to Cdp:
DriverMode::Cdp still uses WebDriver for the session lifecycle but activates
CDP domains so you can call raw CDP commands and use CDP-based helpers.
Activating CDP domains#
Before sending raw CDP commands, activate CDP mode on the session:
This is done automatically by helpers that need CDP, but explicit activation is useful when you send raw commands directly.
CDP helpers on BaseCase#
| Method | Description |
|---|---|
cdp_mouse_click(x, y) | Dispatch a CDP mouse click at viewport coordinates: CSS pixels from the top-left of the visible page, without the scroll position. |
cdp_insert_text(text) | Insert text into whatever has focus with one CDP command (Input.insertText): no key events, no selector, nothing cleared. cdp_type_text is its deprecated old name. |
cdp_click(css) | Scroll the element into view and click its centre with CDP input events. |
cdp_click_element(css) | Deprecated: it is cdp_click. It used to click at the element’s place in the document, so it missed on a scrolled page. |
execute_cdp(method) | Send a raw CDP command with no parameters. |
execute_cdp_with_params(method, params) | Send a raw CDP command with JSON parameters. |
execute_cdp_cmd(command, params) | Alias for execute_cdp_with_params. |
set_network_conditions(conditions) | Throttle the connection via CDP. |
set_timezone(id) | Override the browser timezone via CDP. |
set_geolocation(lat, lon, acc) | Override geolocation via CDP. |
clear_browser_cache() | Clear the HTTP cache via CDP. |
clear_browser_cookies() | Clear cookies via CDP. |
get_cookies() | Return cookies as JSON via CDP. |
cdp_fast_type(selector, text) | Clear the field and insert text in one operation. |
cdp_wait_for_element_present(selector, timeout) | Poll until the element exists in the DOM. |
cdp_select_option_by_index(selector, index) | Select a dropdown option by zero-based index. |
cdp_click(selector) | Wait up to 7 seconds for the element, scroll it into view and click its center with CDP input events. |
cdp_evaluate(expression) | Evaluate JavaScript and return its value, dropping a final return as Python’s sb.cdp.evaluate does; a script that throws is CdpDriver. |
cdp_get_text(selector), cdp_get_attribute(selector, name) | Read an element at once, without waiting; ElementNotFound if it is missing (cdp_wait_for_element_present first for a late one), and None for an attribute it lacks. |
Typing: realistic or fast#
cdp_type sends one key event per character, which is what pages watching for
genuine keyboard input expect. cdp_fast_type clears the field and inserts the
whole string in a single operation: much quicker, but it emits no per-character
key events.
cdp_fast_type is the wrong choice when you are trying not to stand out.
Raw CDP commands#
For operations not covered by the helpers, send raw CDP commands through the underlying session:
execute_cdp sends a command with no parameters. execute_cdp_with_params
accepts a serde_json::Value object of parameters.
Common raw CDP commands#
| Command | Purpose |
|---|---|
Browser.getVersion | Get browser and protocol version. |
Network.setCacheDisabled | Enable or disable the HTTP cache. |
Network.setUserAgentOverride | Override user agent, accept language, and platform. |
Emulation.setDeviceMetricsOverride | Override screen size and device scale factor. |
Emulation.setGeolocationOverride | Override geolocation. |
Emulation.setTimezoneOverride | Override timezone. |
Page.captureScreenshot | Capture a screenshot. |
Network reactor#
The CdpReactor connects to a browser’s debug WebSocket, enables the Fetch
domain, and continues every paused request with custom headers. This lets you
mutate requests in real time without blocking the main WebDriver loop.
What CdpReactor does
CdpReactor::start takes the debugger host, port, and a map of header
overrides. It returns a reactor handle you can stop later with stop().
Network conditions#
Throttle the connection through CDP to simulate slow networks:
Cache and cookies#
Clear the browser cache and cookies via CDP:
When to use CDP mode#
Use CDP mode when:
- A page detects and blocks normal WebDriver commands.
- You need to set custom request headers or throttle the network.
- You want lower-level control over input events and JavaScript evaluation.
- You are building custom anti-detection tooling that needs raw protocol access.
Troubleshooting#
execute_cdp fails
Likely cause: CDP not activated.
Fix: Call activate_cdp_mode() first.
cdp_mouse_click misses
Likely cause: The coordinates are the document’s, not the viewport’s, on a scrolled page.
Fix: Click by selector with cdp_click, which scrolls the element into view first.
Reactor does not intercept
Likely cause: Wrong debugger port.
Fix: Verify the browser was launched with --remote-debugging-port=9222.