# CDP Use (Rust)
Rust implementation of [cdp-use](https://github.com/browser-use/cdp-use) -- a **type-safe Chrome DevTools Protocol client** with auto-generated bindings from the official CDP protocol specifications.
## Features
- **Type-safe commands & events** -- Strongly typed structs for all 53 CDP domains, generated at build time via `build.rs`
- **Async WebSocket client** -- Built on `tokio` + `tokio-tungstenite` with proper timeout, close ordering, and concurrent event dispatch
- **Typed event registration** -- Register async closures for CDP events with full type safety
- **Configurable connection** -- Custom WebSocket frame size, headers, and command timeout via `CdpClientConfig`
- **Zero manual maintenance** -- Code generated directly from `browser_protocol.json` and `js_protocol.json`
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
cdp-use-rs = "0.1"
# or from git
cdp-use-rs = { git = "https://github.com/netkn001/cdp-use-rs" }
```
## Quick Start
```rust
use cdp_use::page;
#[tokio::main]
async fn main() -> Result<(), cdp_use::CdpError> {
// Connect to Chrome running with --remote-debugging-port=9222
let cdp = cdp_use::CdpClient::connect("ws://127.0.0.1:9222/devtools/browser/...").await?;
let send = cdp.send();
let register = cdp.register();
// List targets
let targets = send.target.get_targets(Default::default(), None).await?;
println!("Found {} targets", targets.target_infos.len());
// Attach to a page target
let page_target = targets.target_infos.iter()
.find(|t| t.r#type == "page")
.expect("No page target");
let session = send.target.attach_to_target(
cdp_use::target::commands::AttachToTargetParams {
target_id: page_target.target_id.clone(),
flatten: Some(true),
..Default::default()
},
None,
).await?;
let sid = session.session_id;
// Enable Page domain and register event handler
send.page.enable(Default::default(), Some(&sid)).await?;
register.page.frame_navigated(|event, _session_id| async move {
println!("Navigated: {} -> {}", event.frame.id, event.frame.url);
});
// Navigate
let nav = send.page.navigate(
page::commands::NavigateParams {
url: "https://example.com".into(),
..Default::default()
},
Some(&sid),
).await?;
println!("Frame: {}", nav.frame_id);
cdp.close().await?;
Ok(())
}
```
## Custom Configuration
```rust
use cdp_use::{CdpClient, CdpClientConfig};
use std::time::Duration;
let config = CdpClientConfig {
max_message_size: Some(100 * 1024 * 1024), // 100 MiB (default)
max_frame_size: Some(16 * 1024 * 1024), // 16 MiB
command_timeout: Duration::from_secs(60), // default: 30s
additional_headers: [("Authorization".into(), "Bearer token".into())].into(),
};
let cdp = CdpClient::connect_with_config("ws://...", config).await?;
```
## Architecture
```
cdp-use-rs/
build.rs # Code generator -- reads protocol JSON, emits generated.rs
protocols/
browser_protocol.json
js_protocol.json
src/
lib.rs # Public API re-exports
client.rs # WebSocket client, event registry, CdpClientConfig
error.rs # CdpError enum
examples/
basic.rs # Full usage example
tests/
codegen_test.rs # Type/serialization/config tests
integration_test.rs # Live browser integration tests
```
At build time, `build.rs` parses the CDP protocol JSON files and generates a `generated.rs` containing:
- **Types** -- Structs, enums, and type aliases for each domain (`page::types::Frame`, `network::types::RequestId`, ...)
- **Commands** -- `*Params` / `*Returns` structs and typed async methods on domain clients
- **Events** -- Event structs and typed registration methods
- **CdpLibrary / CdpRegistrationLibrary** -- Top-level accessors: `cdp.send().page.navigate(...)`, `cdp.register().page.frame_navigated(...)`
## Comparison with Other Browser Automation Tools
| **Language** | Java, Python, C#, JS, Ruby | Node.js | Node.js, Python, Java, .NET | Python | **Rust** |
| **Protocol** | WebDriver (W3C) | CDP | CDP + custom protocol | CDP (raw) | **CDP (raw)** |
| **Browser support** | Chrome, Firefox, Safari, Edge | Chrome, Firefox (experimental) | Chrome, Firefox, WebKit | Chrome (any CDP target) | **Chrome (any CDP target)** |
| **Abstraction level** | High-level | High-level | High-level | Low-level (1:1 CDP mapping) | **Low-level (1:1 CDP mapping)** |
| **Type safety** | Varies by language | TypeScript types | TypeScript types | TypedDict + Literal | **Structs + enums + serde** |
| **Auto-wait / retries** | Implicit/explicit waits | Built-in auto-wait | Built-in auto-wait | None (manual) | **None (manual)** |
| **Selectors** | CSS, XPath | CSS, XPath, aria | CSS, XPath, text, role, test-id | N/A (raw CDP) | **N/A (raw CDP)** |
| **Code generation** | N/A | N/A | `codegen` CLI | Runtime script | **Build-time `build.rs`** |
| **CDP domain coverage** | Partial (abstracted away) | Partial (high-level API) | Partial (high-level API) | Full 53 domains | **Full 53 domains** |
| **Use case** | Cross-browser E2E testing | Chrome automation & scraping | Cross-browser E2E testing | Full CDP control, AI agent infra | **Full CDP control, AI agent infra** |
### When to use cdp-use-rs
- You need **direct access to all 53 CDP domains** without abstraction layers getting in the way
- You're building **AI browser agents** or infrastructure that requires low-level protocol control
- You want **compile-time type safety** and **zero-cost abstractions** over the CDP protocol
- Performance matters -- Rust's async runtime and zero-overhead WebSocket handling
- You're integrating CDP into a larger Rust system (e.g., an agent framework, a proxy, or a custom browser controller)
### When to use Playwright / Puppeteer / Selenium instead
- You need **cross-browser support** (Firefox, WebKit/Safari)
- You want **high-level APIs** with built-in auto-wait, selectors, and test assertions
- You're writing **E2E tests** for web applications
- You prefer a batteries-included approach with screenshots, tracing, and network interception out of the box
## Comparison with Python cdp-use
| **Domains** | 53 | 53 |
| **Type system** | `TypedDict` + `Literal` | Structs + enums with serde |
| **Optional fields** | `NotRequired[T]` | `Option<T>` + `skip_serializing_if` |
| **Naming** | camelCase (JS convention) | snake_case + `#[serde(rename_all = "camelCase")]` |
| **Async runtime** | asyncio | tokio |
| **WebSocket** | websockets | tokio-tungstenite |
| **Code generation** | Runtime script | Build-time `build.rs` |
| **Event handlers** | Sync or async callbacks | Async closures (spawned per event) |
## Development
```bash
cargo build # Generates CDP bindings and compiles
cargo test # Run all tests
cargo doc # Generate documentation
# Run the example (requires Chrome with --remote-debugging-port=9222)
cargo run --example basic -- "ws://127.0.0.1:9222/devtools/browser/GUID"
```
## Related
- [cdp-use](https://github.com/browser-use/cdp-use) -- Original Python implementation
- [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) -- Official protocol documentation
- [browser-use](https://github.com/browser-use/browser-use) -- Browser automation framework
## License
MIT