# rust-headless-chrome drives Chrome over the DevTools Protocol from Rust

> A synchronous Rust binding for headless Chrome, honest about the gaps against Puppeteer, with the protocol types generated at build time from a vendored copy of the DevTools schema.

**rust-headless-chrome/rust-headless-chrome** — A high-level API to control headless Chrome or Chromium over the DevTools Protocol. It is the Rust equivalent of Puppeteer, a Node library maintained by the Chrome DevTools team.

- Repository: https://github.com/rust-headless-chrome/rust-headless-chrome
- Stars: 2,952 · Forks: 271
- Language: Rust
- License: MIT
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/rust-headless-chrome-rust-headless-chrome

## The crate is headless_chrome, the repository is not

A small naming detail that catches people out on their first `cargo add`. The repository is rust-headless-chrome/rust-headless-chrome, but the crate published to crates.io is `headless_chrome`, and `Cargo.toml` declares `name = "headless_chrome"` with the lib path at `src/lib.rs`. The badge at the top of the README points at crates.io/crates/headless_chrome and docs.rs/headless_chrome rather than the repository name, which is the confirmation.

The identity behind it is one person. `Cargo.toml` lists the author as Alistair Roche, and the troubleshooting and contribution sections of the README point at a personal email and invite people to open an issue for advice on implementing a missing DevTools feature. That is worth knowing before you plan around a feature: there is a named maintainer to ask, and also no foundation under the project.

The current version is 1.0.22, MIT licensed, edition 2024, with a declared minimum Rust of 1.85. The README notes that SemVer is followed strictly starting from v0.2.0, which is the commitment that makes a 1.x line safe to depend on. GitHub reports roughly 2950 stars, 271 forks, 144 open issues, and a last push on 2026-06-11, the same day as the 1.0.22 release that added a default timeout for `Browser` and moved to rustls with webpki roots.

## A blocking API built on threads, not an async runtime

The quick start is a single synchronous function. You construct a browser, open a tab, navigate, wait for an element, type, and assert:

```rust
use headless_chrome::Browser;
use headless_chrome::protocol::cdp::Page;
```

```rust
    let browser = Browser::default()?;

    let tab = browser.new_tab()?;

    tab.navigate_to("https://www.wikipedia.org")?;

    tab.wait_for_element("input#searchInput")?.click()?;
```

Two consequences follow from the type signatures. Every fallible step returns a `Result`, and every wait blocks until the condition holds or a timeout expires, which is why a configurable default timeout on `Browser` was worth a release note. Nothing here needs a runtime, a `select!` loop or a spawner.

That design is the main philosophical difference from the alternatives, and the README does not pretend otherwise. In the related crates section it describes its own API as synchronous and implemented using plain old threads, and contrasts that with fantoccini, which is asynchronous and based on Tokio. If your existing program is already async, mixing a blocking browser driver into it is a real architectural decision, not a detail, and the crate does not offer an async mode.

## Protocol types are generated at build time, and offline by default

This is the packaging detail that explains how a small crate can stay current with a large protocol. The build dependency is `auto_generate_cdp`, listed at version 0.4.6, and the tree contains a `json/` directory holding the DevTools protocol definitions. The default feature is `offline`, which maps to `auto_generate_cdp/offline`, meaning the binding generation works from that vendored copy rather than reaching out to the network during a build.

That default is a good choice for reproducible builds, and it is also the reason the crate does not need network access to compile:

```toml
[features]
default = ["offline"]
fetch = ["ureq", "directories", "zip", "walkdir"]
nightly = []
```

The `fetch` feature is unrelated to protocol types, which is a naming collision worth watching for. It enables the dependency set behind the README's automatic downloading of known good Chromium binaries for Linux, Mac and Windows, using `ureq` for HTTP, `zip` for the archive, `walkdir` to unpack it and `directories` to find a cache location. The README's own snippet for it points at the git repository rather than the registry:

```toml
[dependencies]
headless_chrome = {git = "https://github.com/rust-headless-chrome/rust-headless-chrome", features = ["fetch"]}
```

TLS roots come in two flavours as optional features, `rustls-tls-native-roots` and `rustls-tls-webpki-roots`, the latter pairing rustls with bundled webpki roots. That matches the 1.0.22 release moving to rustls and webpki roots. The dependency list is otherwise modern and mostly current versions, and there is a Windows-specific `winreg` entry.

## What it cannot do is listed, which is rarer than it sounds

Most browser automation wrappers advertise coverage. This README has a section headed What can't it do, and it is specific. The Chrome DevTools Protocol is huge, the README says Puppeteer supports much more of it, and then it names the gaps: dealing with frames, file picker and chooser interactions, touchscreen tapping, network condition emulation, reading timing information about network requests, reading the SSL certificate, replaying XHRs, HTTP Basic Auth, inspecting `EventSource` streams, and WebSocket inspection.

That list is a project plan as much as a limitation disclosure. Several items on it are things a browser test suite needs, frames most obviously, which is why the missing-frames entry is the one to check first against your own requirements.

What the project does claim, beyond basic driving, is a solid list: network request interception, JavaScript coverage monitoring through `take_precise_js_coverage`, incognito windows, screenshots of an element or the whole page, saving pages to PDF, headful browsing as an option on the launch builder, extension pre-loading, and the binary auto-download described earlier. The quick start demonstrates the interesting combination, running JavaScript in the page against a found element with `call_js_fn` where `this` is the element the call was made on, then screenshotting that element on its own as well as the full window.

## How the alternatives are described, and timeouts in containers

The README recommends a competitor in plain language. Of fantoccini it says it uses WebDriver so it works with browsers other than Chrome, that it is asynchronous and Tokio-based, that it has been around longer, and that it is more battle-tested. It adds the counterweight: fantoccini does not support Chrome DevTools-specific functionality such as JavaScript coverage. That framing is the honest way to choose, because the two projects really do optimize for different targets, and being told which one is more battle-tested by the other project's maintainer is useful information.

Container deployment has one documented failure mode. If you hit errors related to timeouts, the README says you likely need to enable sandboxing either in the kernel or as a setuid sandbox, and points to Puppeteer's troubleshooting documentation. This is the same Chrome sandbox requirement that affects most headless setups, and it is the first thing to check when the driver appears to hang in Docker.

For debugging, the crate uses the `log` facade, and the README asks you to set two environment variables before running the tests:

```rust
RUST_BACKTRACE=1 RUST_LOG=headless_chrome=trace
```

The tree has `examples/` and `tests/`, and the README points at `tests/simple.rs` as the fuller example, while noting that the examples need the `failure` crate added to your `Cargo.toml` dependencies first.

## Conclusion

The decision here is less about features than about shape. rust-headless-chrome gives you a blocking API implemented with plain threads, and it states plainly that it does not cover the whole DevTools Protocol and that the alternatives it names have been around longer. If you want the widest protocol coverage from a non-Node ecosystem, the recommendation belongs to fantoccini through WebDriver, which trades Chrome-specific features like JavaScript coverage for any browser. If you specifically want CDP, request interception, JS coverage, incognito windows and page or element screenshots in a blocking API, this crate is the more direct fit. The build-time protocol generation from the vendored `json/` directory is the detail most likely to surprise you, and the `fetch` feature is the one you are most likely to want to switch on. Begin with `Browser::default()`, then read the crate's list of what it cannot do before you scope a project around it.

## FAQ

### What does "headless Chrome" mean?

Chrome running without a visible window, driven programmatically instead of by a person, so pages can be loaded, queried, screenshotted and rendered to PDF by code. This crate is the Rust layer on top of that idea: it launches a headless or headful browser and speaks the Chrome DevTools Protocol to it, and it is presented as the Rust equivalent of Puppeteer.

### What headless browser is written in Rust?

This crate is one: `headless_chrome`, published on crates.io, which drives Chrome or Chromium over the DevTools Protocol. The README also names fantoccini, which is asynchronous and Tokio-based and goes through WebDriver, so it can drive browsers other than Chrome, at the cost of the DevTools-specific features such as JavaScript coverage.

### What are the disadvantages of using a headless browser?

For this crate the documented disadvantages are coverage gaps and API shape. The README says it is not fully feature compatible with Puppeteer and lists what is missing, including frame handling, file picker interactions, network condition emulation, HTTP Basic Auth and WebSocket inspection. Its API is also synchronous and built on plain threads, which does not sit naturally inside an async program.

## Sources

- [Issues](https://github.com/rust-headless-chrome/rust-headless-chrome/issues)
- [License: MIT](https://github.com/rust-headless-chrome/rust-headless-chrome/blob/main/LICENSE)
- [README](https://github.com/rust-headless-chrome/rust-headless-chrome/blob/main/README.md)
- [Releases](https://github.com/rust-headless-chrome/rust-headless-chrome/releases)
- [rust-headless-chrome/rust-headless-chrome on GitHub](https://github.com/rust-headless-chrome/rust-headless-chrome)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rust-headless-chrome-rust-headless-chrome
