Skip to main content

chrome-remote-interface

chrome-remote-interface is a low-level, asynchronous Python client for the Chrome DevTools Protocol (CDP). It is a Python port of the Node.js chrome-remote-interface package.

The library gives you direct access to Chrome and Chromium debugging domains over WebSocket. It intentionally stays close to CDP: it does not add browser automation concepts such as locators, page objects, or selectors.

Features

  • Async WebSocket client built for asyncio.
  • One generated, typed Python module for every CDP domain.
  • Typed commands, parameters, results, events, payloads, aliases, and enums.
  • Event listeners with either callbacks or awaitable one-shot waits.
  • Flattened CDP sessions through the session_id argument.
  • Chrome discovery helpers compatible with the Node.js package.
  • Raw client.send(...) access for protocol additions not in the bundled schema.
  • Command-line tools for listing targets, creating targets, and inspecting a running browser.

Requirements

  • Python 3.10 or newer.
  • Chrome or Chromium started with remote debugging enabled.

Install the package from PyPI:

python -m pip install chrome-remote-interface

Start a debugging browser on the default endpoint (localhost:9222):

chrome --remote-debugging-port=9222

For a separate profile, add --user-data-dir so that the command can run next to an existing Chrome instance. See examples/README.md for a complete setup and runnable examples.

Quick start

The package is installed as chrome-remote-interface but imported as cdp:

import asyncio

from cdp import connect


async def main() -> None:
    client = await connect()
    try:
        await client.Page.enable()

        loaded = client.Page.loadEventFired()
        navigation = await client.Page.navigate(url="https://example.com")
        await loaded
        print(f"Loaded frame: {navigation['frameId']}")
    finally:
        await client.close()


asyncio.run(main())

Every command can use keyword arguments or a parameter mapping. Generated domain methods return typed dictionaries, so editors can provide completion and report incorrect fields before runtime.

Events and JavaScript

Subscribe to a typed event with a callback and keep the unsubscribe function:

from cdp.domains.network import RequestWillBeSentEvent


def on_request(event: RequestWillBeSentEvent) -> None:
    print(event["request"]["url"])


unsubscribe = client.Network.requestWillBeSent(on_request)
await client.Network.enable()

# Later:
unsubscribe()

CDP values can be optional according to the protocol schema. Narrow them before indexing them:

result = await client.Runtime.evaluate(
    expression="document.title",
    returnByValue=True,
)
remote_object = result["result"]
if "value" in remote_object:
    print(remote_object["value"])

Targets and sessions

The HTTP helpers can list inspectable targets and connect to a specific page:

from cdp import List, connect


targets = await List()
page = next(target for target in targets if target["type"] == "page")
client = await connect(page["id"])

For browser-level connections, attach to a target and pass its session ID to subsequent domain commands:

from cdp import Version, connect


version = await Version()
browser = await connect(version["webSocketDebuggerUrl"])
created = await browser.Target.createTarget(url="about:blank")
attached = await browser.Target.attachToTarget(
    targetId=created["targetId"],
    flatten=True,
)
await browser.Page.enable(session_id=attached["sessionId"])

Discovery helpers

The following async helpers use Chrome's /json endpoints and default to localhost:9222:

Helper Purpose
Version() Browser version and browser WebSocket URL
List() List inspectable targets
New() Create a new target
Activate() Activate a target
Close() Close a target
Protocol() Fetch the browser's protocol descriptor

Each helper accepts options such as host, port, secure, and timeout. The Node-compatible aliases (Chrome, CDP, list_targets, and so on) are also exported.

Generated CDP domains

Where protocol.json comes from

The source descriptor is chrome-remote-interface/lib/protocol.json. It is the merged Chrome DevTools Protocol schema: Chrome's browser domains plus the JavaScript/runtime domains from the upstream devtools-protocol repository. The copy at cdp/protocol.json is generated automatically for Protocol({"local": True}); do not edit that copy by hand.

Updating the schema

To use the exact protocol supported by a running Chrome, first start Chrome with remote debugging and download its descriptor:

Invoke-WebRequest `
    -Uri http://localhost:9222/json/protocol `
    -OutFile chrome-remote-interface/lib/protocol.json

Or, from Git Bash, run the repository's update script to fetch and merge the latest upstream schema used by the original Node.js project:

bash scripts/update-protocol.sh

The script writes the source descriptor and regenerates the Python bindings automatically. If you only replace the source file manually, regenerate from the repository root with:

python tools/generate_domains.py

The generator validates the descriptor, copies it to cdp/protocol.json, and writes one module per domain under cdp/domains/:

from cdp.domains.page import NavigateParameters, NavigateResult
from cdp.domains.runtime import RemoteObject

tools/generate_stubs.py remains available as a compatibility entry point. When a connected browser advertises newer protocol members, use client.send("Domain.command", ...) as a typed-safe raw fallback.

Examples

The examples/ directory contains small, runnable programs:

  • basic_navigation.py — Page.enable, Page.navigate, and load events.
  • evaluate.py — Runtime.evaluate and optional result values.
  • network_events.py — typed Network request events.
  • target_sessions.py — Target creation, attachment, and sessions.

Run them from the repository root with:

python -m examples.basic_navigation

Command-line interface

The package also installs a chrome-remote-interface command:

chrome-remote-interface list
chrome-remote-interface new https://example.com
chrome-remote-interface protocol --local
chrome-remote-interface inspect

Development

Install development dependencies and run the full validation suite:

python -m pip install -e ".[dev]"
python tools/generate_domains.py
python -m unittest discover -s tests
ruff format --check .
ruff check .
pyright
python -m build

License

This project is distributed under the MIT License.

Metadata

Release files for chrome-remote-interface 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chrome-remote-interface 1.0.1
File Size Uploaded Provenance Actions
chrome_remote_interface-1.0.1.tar.gz 324.6 kB Without provenance Details for chrome_remote_interface-1.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for chrome-remote-interface 1.0.1
File Interpreter ABI Platform Actions
chrome_remote_interface-1.0.1-py3-none-any.whl Python 3 none any Details for chrome_remote_interface-1.0.1-py3-none-any.whl

Total release size: 683.4 kB

Release files / chrome_remote_interface-1.0.1.tar.gz

Download URL chrome_remote_interface-1.0.1.tar.gz
Size 324.6 kB
Tags Source
SHA-256 checksum
How to use checksums
a8e7675e4cd274039d4b0420d9fc2749ecf88359f74fc2219779f46fa59c749d
BLAKE2b-256 checksum
How to use checksums
cca8a8011cbf192986e2104242c17e746f043fbd55e7108211bff36b1a7c311e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / chrome_remote_interface-1.0.1-py3-none-any.whl

Download URL chrome_remote_interface-1.0.1-py3-none-any.whl
Size 358.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6af2a95c7f3661a2af1d3b424226351df1be37287e5d5dfad963a368665fd7c5
BLAKE2b-256 checksum
How to use checksums
741d45038d8324fe84a6c7be06fae5ca8d9eb560db10f8f0d01c41412782f5b3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Security for chrome-remote-interface 1.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page