Rust language bindings for Microsoft Playwright — the industry standard for cross-browser end-to-end testing.
Status: Pre-1.0, API stabilizing. See coverage for the path to v1.0.
This README describes the latest published release on crates.io. For unreleased changes on
main, see the CHANGELOG under[Unreleased].
Rust is emerging as a serious web development language, AI coding
assistants are making it accessible to more developers, and test-driven
development works well with AI agents. Those trends need production-quality
E2E testing, and playwright-rust fills that gap (WHY.md has the
fuller case). The goal is official-quality Rust bindings following the same
architecture as
playwright-python,
playwright-java, and playwright-dotnet; see the
development roadmap for plans and status.
If you know playwright-python, you know playwright-rust:
| Python | Rust |
|---|---|
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://example.com")
# Locator with auto-waiting
heading = page.locator("h1")
assert heading.text_content() == "Example Domain"
# Response body access
resp = page.goto("https://api.example.com/data")
data = resp.json()
browser.close() |
use playwright_rs::Playwright;
let pw = Playwright::launch().await?;
let browser = pw.chromium().launch().await?;
let page = browser.new_page().await?;
page.goto("https://example.com", None).await?;
// Locator with auto-waiting
let heading = page.locator("h1").await;
assert_eq!(heading.text_content().await?, Some("Example Domain".into()));
// Response body access
let resp = page.goto("https://api.example.com/data", None).await?.unwrap();
let data: serde_json::Value = resp.json().await?;
browser.close().await?; |
Full Python API parity + agent integration. All Playwright Python classes
and methods are implemented, plus Browser::bind() / Browser::unbind()
(Playwright 1.59) for exposing a Rust-launched browser to external clients
like @playwright/mcp, the Playwright CLI, or third-party agent tooling.
Chromium, Firefox, and WebKit are tested in CI on Linux, macOS, and Windows.
The remaining path to v1.0 is multi-month dogfooding, API polish, and performance tuning rather than new surface area. See the v1.0 gap analysis for the detailed state of each class.
One known limitation: WebKit launch_persistent_context() fails on native
Windows (upstream issue
microsoft/playwright#36936,
tracked here as #39).
Non-persistent WebKit works on Windows; use WSL or macOS/Linux otherwise.
playwright-rust follows Microsoft's architecture for language bindings:
┌──────────────────────────────────────────────┐
│ playwright-rs (Rust API) │
│ - High-level, idiomatic Rust API │
│ - Async/await with tokio │
│ - Type-safe bindings │
└─────────────────────┬────────────────────────┘
│ JSON-RPC over stdio
┌─────────────────────▼────────────────────────┐
│ Playwright Server (Node.js/TypeScript) │
│ - Browser automation logic │
│ - Cross-browser protocol abstraction │
│ - Maintained by Microsoft Playwright team │
└─────────────────────┬────────────────────────┘
│ Native protocols
┌─────────────┼─────────────┐
▼ ▼ ▼
Chromium Firefox WebKit
The crate is a thin JSON-RPC client to the same server the official
bindings use, so feature parity and protocol maintenance come from upstream
rather than being reimplemented here. The API diverges only where Rust
idiom allows a better shape (Result<T>, builders for option-heavy
methods, compile-time-validated selectors).
Add to your Cargo.toml:
[dependencies]
playwright-rs = "0.17" # Auto-updates to latest 0.17.x
tokio = { version = "1", features = ["full"] }The default-on macros feature re-exports the
locator!() compile-time selector
macro. The default-on ring feature selects the crypto backend for driver
downloads (and for rustls WebSocket connections); use aws-lc instead when
AWS-LC is required:
playwright-rs = { version = "0.17", default-features = false, features = [
"aws-lc",
"native-tls",
"macros",
] }Disabling default features requires selecting either ring or aws-lc.
Other opt-in features are cli (installer binary, see below) and
screenshot-diff (pixel-diff assertions). For programmatic trace-zip
inspection, add playwright-rs-trace
as a [dev-dependencies] entry.
Browsers install once; the library bundles a specific Playwright driver,
and each driver release expects matching browser builds. Install through
the crate itself so the match is guaranteed and the browser version rides
Cargo.lock: copy
examples/install-browsers.rs
into your project's examples/ directory (it needs tokio with the
macros and rt-multi-thread features), then:
cargo run --example install-browsers # all browsers
cargo run --example install-browsers -- chromium firefox # or a subsetPass --with-deps to also install the system libraries the browsers need
(Linux CI typically wants this; it runs the package manager under sudo).
Without the flag only browsers install, on every platform, matching
npx playwright install.
In CI, the same command runs before the test step:
- name: Install Playwright browsers
run: cargo run --example install-browsers -- chromium firefox webkitWhen dependabot bumps playwright-rs, the crate, driver, and browsers move
together with no workflow edit. Never hardcode a Playwright version in a
workflow run: step or a package.json: dependabot can't see the former
and bumps the latter on npm's cadence, not the crate's. The driver ships its
own Node.js runtime, so no setup-node step is needed. For setup scripts and
Docker builds, call
install_browsers
directly. Outside a Cargo project, the cli feature provides an installer
binary (cargo install playwright-rs --features cli, then
playwright-rs install).
This repo ships an Agent Skill so your agent writes
against this crate's actual API model instead of guessing from generic
Playwright knowledge. It covers adding the dependency and installing
browsers, the object model, the builder and locator!() conventions,
auto-wait semantics, and capturing a trace when something fails.
npx skills add padamson/playwright-rustWorks with Claude Code, Codex, Cursor, and any other compatible agent.
Claude Code can also install it as a plugin, which tracks this repo:
/plugin marketplace add padamson/playwright-rust
/plugin install playwright-rs@playwright-rustThird-party marketplaces don't refresh on their own; update with
/plugin marketplace update playwright-rust followed by
/plugin update playwright-rs@playwright-rust.
The skill lives at
skills/playwright-rs-usage/ and points back
at docs.rs and the
examples for the API surface itself. A build
gate keeps it honest: its code compiles against the real crate, and it
cannot omit a cargo feature or browser engine the crate exposes.
Building from source, running the test suite, and debugging failures (backtraces, saving a Playwright trace on failure) are covered in docs/development.md.
Contributions should follow Playwright API conventions, include tests, document public APIs with examples, and pass CI (fmt, clippy, tests).
Apache-2.0 (same as Microsoft Playwright). Thanks to the Microsoft Playwright team for the framework and the server this crate drives, and to playwright-python for the API design reference.