Skip to content

CDP Executors

Eduard Dik edited this page Feb 4, 2026 · 2 revisions

CDP Executors Overview

While standard Selenium provides high-level commands, many advanced features (like detailed network interception, precise emulation, or performance monitoring) are only available via the Chrome DevTools Protocol (CDP).

The executors package provides a unified bridge to CDP, handling the complexity of protocol versioning and asynchronous execution.


Version-Aware Architecture

CDP changes as Chrome/Chromium updates. A command that works in version 140 might behave differently or be renamed in version 144.

osn-selenium solves this by providing version-specific executors. The library currently supports a range from v140 to v144. Accessing them is as simple as calling the corresponding property on the cdp object:

from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver

driver = ChromeWebDriver(webdriver_path="./chromedriver")

# Accessing version 144 domains
executor = driver.cdp.v144

Lazy Loading

The framework uses Lazy Loading for CDP modules. It does not import version-specific logic until you actually call it. This keeps the initial library memory footprint low and prevents errors if you don't have all versioned packages installed.


Dependency Management (CDPPackageError)

To keep the core library lightweight, versioned CDP logic is stored in separate external packages (e.g., osn-selenium-cdp).

If you attempt to access a version that is not installed on your system, the executor will raise a CDPPackageError. This error is helpful—it checks GitHub for the existence of that version and provides the exact pip command to fix the issue:

Error Example: CDPpackage for v144 is not installed. Fix: Run the following command: pip install git+https://github.com/oddshellnick/osn-selenium-cdp.git@v144


Synchronous vs. Asynchronous Execution

The CDP Executor adapts to the architecture of your driver.

Synchronous Mode (osn_selenium/executors/sync/cdp)

In synchronous drivers, CDP commands are executed immediately through a bridge that interacts with the underlying Selenium driver.

from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver

driver = ChromeWebDriver(webdriver_path="./chromedriver")

# Sync driver example
driver.cdp.v144.page.navigate(url="https://example.com")

Asynchronous Threaded Mode (osn_selenium/executors/trio_threads/cdp)

In Trio-based drivers, every CDP call is automatically wrapped in a thread-safe task. You must use the await keyword, and the executor ensures that the command respects the trio.Lock and CapacityLimiter of the driver instance.

from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver

driver = ChromeWebDriver(webdriver_path="./chromedriver")

# Trio driver example
await driver.cdp.v144.emulation.set_geolocation_override(
    latitude=48.8584, 
    longitude=2.2945, 
    accuracy=100
)

Asynchronous BiDi Mode (osn_selenium/executors/trio_bidi/cdp)

In trio_bidi drivers, the executor is powered by the BiDi Mapping. Calls are routed to the CDPExecutor which uses the connection pool to send goog:cdp.sendCommand via the WebSocket. This is highly efficient as it bypasses the HTTP overhead of the ChromeDriver entirely.

from osn_selenium.webdrivers.trio_bidi.chrome import ChromeWebDriver

driver = ChromeWebDriver(webdriver_path="./chromedriver")

# Direct WebSocket Command
await driver.cdp.v144.target.get_targets()

The Bridge Mechanism

Under the hood, the executors use a "Bridge" function (get_cdp_executor_bridge). This bridge performs several critical tasks:

  1. Unwrapping: It extracts raw Selenium objects from your Python wrappers before sending the command.
  2. Execution: It calls the native execute_cdp_cmd method of the WebDriver.
  3. Wrapping: It takes the selenium result from the browser and wraps any returned objects back into the framework's Sync or TrioThread models.

Usage Example

Here is how you would use the CDP Executor to simulate a slow 3G connection:

from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver

driver = ChromeWebDriver(webdriver_path="./chromedriver")

# Enable network domain
driver.cdp.v144.network.enable()

# Set throttling conditions
driver.cdp.v144.network.emulate_network_conditions(
    offline=False,
    latency=100,            # 100ms
    download_throughput=750 * 1024, # 750kb/s
    upload_throughput=250 * 1024,   # 250kb/s
    connection_type="cellular3g"
)

Versioned Packages & Custom CDP Support

Official Supported Versions

All officially maintained and pre-generated CDP packages can be found in the following repository:
🔗 osn-selenium-cdp

You can check available branches (v140, v141, etc.) to see which protocol versions are ready for installation.

Generating Custom Protocols

If you are using a very new or highly specific version of Chromium that isn't yet available in the official repository, you can generate your own CDP wrapper package using:
🔗 osn-selenium-package-parser (it will be public soon)

This tool parses the Chrome protocol definition and creates a compatible Python package structure that integrates seamlessly with the framework.

Local Integration & Custom Paths

Every WebDriver class in the framework (Chrome, Edge, Yandex) provides two specific parameters to manage custom or local CDP packages without requiring them to be installed in your global site-packages:

  • cdp_versioned_packages_paths: A mapping (dictionary) where the key is the version integer (e.g., 145) and the value is the local filesystem path to your generated package.
  • ignore_cdp_version_package_missing: A boolean flag (default True). If set to False, the library will immediately raise an error if the requested CDP version is not found, rather than attempting to fall back or ignore it.

Example of using a local custom CDP package:

from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver

driver = ChromeWebDriver(
    webdriver_path="./chromedriver",
    cdp_versioned_packages_paths={
        145: "/home/user/my_custom_cdp_v145"
    },
    ignore_cdp_version_package_missing=False
)

This mechanism uses a custom MetaPathFinder (the CDP Import Hook) to redirect Python's import system to your specified local directory whenever driver.cdp.v145 is accessed.

Clone this wiki locally