Introduction
zendriver-rs is an async-first, undetectable browser-automation library for Rust. It drives a real Chrome instance over the Chrome DevTools Protocol (CDP) directly — no WebDriver shim, no Selenium grid, no JSON wire — and ships with anti-detection patches that pass mainstream fingerprint batteries out of the box.
It is a Rust port of the Python zendriver / nodriver projects, with
the API redesigned around Rust's type system: builder patterns where Python
uses kwargs, traits where Python uses duck-typed protocols, Result where
Python uses exceptions, and explicit lifetimes for query scopes that the
borrow checker tracks instead of letting them drift across await points.
Use cases
- Scraping sites that block headless browsers. The
spoofedstealth profile patchesnavigator.webdriver, the Chrome runtime object, the permissions API, and a half-dozen other tells. Cloudflare Turnstile, PerimeterX, and DataDome challenges pass without manual headers. - End-to-end testing of real-world web apps. First-class multi-tab,
cross-origin iframe (OOPIF) support, network interception, and a
Playwright-style
expect()pre-register surface make whole-flow tests expressive without the wire-protocol churn of WebDriver. - Browser automation pipelines under load. Tab handles are `Send + Sync
- Clone
, the transport is a single Tokio actor, and queries are zero-copy&strselectors — comfortable inside anytokio::spawn`'d worker pool.
- Clone
- Drop-in replacement for
chromiumoxidecallers who want stealth, multi-tab, and an ergonomicfind().css("...").one()query surface instead of hand-rollingPage.querySelectorcalls.
What makes it different
- CDP-direct. Every method maps to one or two CDP commands. There is no WebDriver-style adapter layer, so latency is one network round-trip per call — typically under 1 ms on localhost.
- Undetectable by default.
StealthProfile::nativeis the suggested starting point — UA scrub plus Emulation overrides, no JS bootstrap, no prototype patching.StealthProfile::spoofedadds Navigator-prototype patches that pass sannysoft + areyouheadless. Off-by-default forStealthProfile::offwhen you want a vanilla browser for reproduction. - Async-first. Built on Tokio. Every call returns a
Future. No blocking, noblock_on, notokio::task::spawn_blocking. Browser / Tab / Element handles areClone + Send + Syncso they cross.awaitboundaries and task spawns without ceremony. - Rust-native. Errors are typed via
thiserrorand surfaced throughResult. Selectors are checked at call time, not parsed at startup. Resources clean up viaDrop(Chrome subprocess getsSIGTERMwhen the lastBrowserclone drops). The borrow checker tracks query scopes for you.
Comparison
| feature | zendriver-rs | chromiumoxide | thirtyfour | fantoccini |
|---|---|---|---|---|
| Transport | CDP-direct | CDP-direct | WebDriver | WebDriver |
| Stealth out of the box | yes | no | no | no |
| Builder-style queries | yes | partial | no | no |
| Cross-origin iframes | yes | partial | yes | yes |
| Send+Sync handles | yes | yes | yes | yes |
| Async runtime | Tokio | async-std/Tokio | Tokio | Tokio |
| Network interception | yes | yes | limited | limited |
| Multi-tab orchestration | yes | manual | manual | manual |
Comparisons against Playwright + Selenium are covered in Migration from Playwright.
How this book is organized
- Setup chapters — Install and Quickstart cover the minimum needed to write your first script.
- Core API chapters — Stealth, Multi-tab, Frames, and Input cover the always-on Browser/Tab/Element surface.
- Optional-feature chapters — Interception, Expect(), Cloudflare, and Fetcher cover the gated Cargo features.
- Reference chapters — Architecture, Migration from Playwright, FAQ, and Error Reference round out the long tail.
The API rustdoc on docs.rs/zendriver is the source of truth for the public surface. The book covers the how and why; rustdoc covers the what.