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.

Publishing a release

The workflow in .github/workflows/publish.yml validates and publishes a package to PyPI whenever a tag matching v* is pushed. It uses PyPI Trusted Publishing (GitHub Actions OIDC), so no API token is stored in the repository.

Before the first release, configure a PyPI Trusted Publisher for this GitHub repository with workflow publish.yml and environment pypi. Then bump the version in pyproject.toml, commit it, and push a matching unique tag:

git tag v1.0.2
git push origin v1.0.2

The workflow rejects tags whose version does not match pyproject.toml.

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, 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.3

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.3
File Size Uploaded Provenance Actions
chrome_remote_interface-1.0.3.tar.gz 327.0 kB With provenance Details for chrome_remote_interface-1.0.3.tar.gz

Built distribution (wheel)

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

Total release size: 687.1 kB

Release files / chrome_remote_interface-1.0.3.tar.gz

Download URL chrome_remote_interface-1.0.3.tar.gz
Size 327.0 kB
Tags Source
SHA-256 checksum
How to use checksums
4068c58d9276e1258b08357c01ee5ae68687ef66a9cc32cc857753cc94516147
BLAKE2b-256 checksum
How to use checksums
d6c37581585848d83970d7d3c475522de2689953407e0ed7b4213d89d3faedad
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 Jul 31, 2026.

Transparency log

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

Download URL chrome_remote_interface-1.0.3-py3-none-any.whl
Size 360.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b5b7644da1403a8d959bdd864b182365b5319499d8eba3127599afd3c090dc90
BLAKE2b-256 checksum
How to use checksums
b53af5dd819400118ae2789f021fae68a75d745521dff401bbdbec95a5d3bf86
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 Jul 31, 2026.

Transparency log

Security for chrome-remote-interface 1.0.3

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.3.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 Jul 31, 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