Cdp-use: type-safe Python client for the CDP Chrome DevTools Protocol (CDP)
4 months ago
1
A type-safe Python client generator for the Chrome DevTools Protocol (CDP). This library automatically generates Python bindings with full TypeScript-like type safety from the official CDP protocol specifications.
🔒 Type Safety: Full type hints with TypedDict classes for all CDP commands, parameters, and return types
🏗️ Auto-Generated: Code generated directly from official Chrome DevTools Protocol specifications
🎯 IntelliSense Support: Perfect IDE autocompletion and type checking
📦 Domain Separation: Clean organization with separate modules for each CDP domain (DOM, Network, Runtime, etc.)
🔄 Always Up-to-Date: Easy regeneration from latest protocol specs
🚫 No Runtime Overhead: Pure Python types with no validation libraries required
The generator creates a complete type-safe CDP client library:
git clone https://github.com/browser-use/cdp-use
cd cdp-use
uv sync # or pip install -r requirements.txt
Generate the CDP client library:
python -m cdp_use.generator.generate
This automatically downloads the latest protocol specifications and generates all type-safe bindings.
importasynciofromcdp_use.clientimportCDPClientasyncdefmain():
# Connect to Chrome DevToolsasyncwithCDPClient("ws://localhost:9222/devtools/browser/...") ascdp:
# Get all browser targets with full type safetytargets=awaitcdp.send.Target.getTargets()
print(f"Found {len(targets['targetInfos'])} targets")
# Attach to a page targetpage_target=next(tfortintargets["targetInfos"] ift["type"] =="page")
session=awaitcdp.send.Target.attachToTarget(params={
"targetId": page_target["targetId"],
"flatten": True
})
# Enable DOM and get document with type safetyawaitcdp.send.DOM.enable(session_id=session["sessionId"])
document=awaitcdp.send.DOM.getDocument(
params={"depth": -1, "pierce": True},
session_id=session["sessionId"]
)
print(f"Root node ID: {document['root']['nodeId']}")
asyncio.run(main())
The generated library provides complete type safety:
# ✅ Fully typed parametersawaitcdp.send.Runtime.evaluate(params={
"expression": "document.title",
"returnByValue": True,
"awaitPromise": True
})
# ✅ Optional parameters work correctlyawaitcdp.send.Target.getTargets() # No params needed# ✅ Return types are fully typedresult=awaitcdp.send.DOM.getDocument(params={"depth": 1})
node_id: int=result["root"]["nodeId"] # Full IntelliSense support# ❌ Type errors caught at development timeawaitcdp.send.DOM.getDocument(params={"invalid": "param"}) # Type error!
# Execute multiple CDP commands concurrently with type safetytasks= [
cdp.send.DOM.getDocument(params={"depth": -1}, session_id=session_id)
for_inrange(10)
]
results=awaitasyncio.gather(*tasks)
print(f"Completed {len(results)} concurrent requests")
Domain Libraries: Each CDP domain (DOM, Network, Runtime, etc.) gets its own client class
Type Definitions: Complete TypedDict classes for all CDP types, commands, and events
Main Library: CDPLibrary class that combines all domain clients
Type Safety: All method signatures use quoted type annotations to avoid runtime evaluation
Commands with all-optional parameters are handled correctly:
# These work without type errors:awaitcdp.send.Target.getTargets() # No paramsawaitcdp.send.Target.getTargets(params=None) # Explicit Noneawaitcdp.send.Target.getTargets(params={"filter": ...}) # With params
Cross-Domain Type References
Types are properly imported across domains using TYPE_CHECKING blocks to avoid circular imports.
Fork the repository
Make your changes to the generator code (not the generated cdp_use/cdp/ directory)
Run python -m cdp_use.generator.generate to regenerate the library