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())

connect() applies its timeout to discovery and the WebSocket handshake. For long-running commands, set command_timeout to bound how long a command may wait for a response. A timed-out command is cancelled and removed from the pending-request table:

client = await connect(command_timeout=10)
try:
    await client.Page.enable()
finally:
    await client.close()

The connection close handshake is bounded by close_timeout (five seconds by default). You can also use the async context manager to guarantee cleanup:

client = await connect()
async with client:
    await client.Page.enable()

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()

Listeners registered with a session_id are removed automatically when Chrome emits Target.detachedFromTarget. They can also be removed explicitly with client.remove_session_listeners(session_id).

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 run the repository's Python update script to fetch and merge the latest upstream schema used by the original Node.js project:

python scripts/update_protocol.py

The base URL can be overridden with CDP_PROTOCOL_BASE_URL or the --base-url option.

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.5

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.5
File Size Uploaded Provenance Actions
chrome_remote_interface-1.0.5.tar.gz 383.8 kB With provenance Details for chrome_remote_interface-1.0.5.tar.gz

Built distribution (wheel)

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

Total release size: 803.3 kB

Release files / chrome_remote_interface-1.0.5.tar.gz

Download URL chrome_remote_interface-1.0.5.tar.gz
Size 383.8 kB
Tags Source
SHA-256 checksum
How to use checksums
0b43d7ec9ee34ed8869bea311bb3c61361ce90c3d62ae67b77a438deb027f978
BLAKE2b-256 checksum
How to use checksums
501f5035ece739457c2b721b395d1c7b966d43dc946907fe58e99e7924d69644
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

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

Download URL chrome_remote_interface-1.0.5-py3-none-any.whl
Size 419.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bb65c2497dfc63382fdfb4988dc236c76fd62c00d51e76c85e8bef30a7445369
BLAKE2b-256 checksum
How to use checksums
17e008a0dab572e887ead00ffc08329edcb122ab50617053a0824783315840be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Security for chrome-remote-interface 1.0.5

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for chrome_remote_interface-1.0.5.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

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