A Rust-backed, CDP-first Python automation library with a Playwright-compatible sync API
Project description
Change one import and your existing Playwright code — Python or Node — runs on an in-process Rust CDP engine. No Node driver subprocess. No Playwright fingerprint.
Change one import
Rustwright is a drop-in for existing Playwright code — in most cases the import is the only line that changes.
Python
- from playwright.sync_api import sync_playwright
+ from rustwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://example.com")
print(page.title())
browser.close()
Node.js
- import { chromium } from 'playwright';
+ import { chromium } from 'rustwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.title());
await browser.close();
515/515 shared parity cases pass against real Playwright (growing suite; full behavioral parity in progress). rustwright.async_api mirrors Playwright's async API (concurrency notes in Limitations).
Prefer not to touch imports at all? Python offers an opt-in shim — rustwright.enable_playwright_compat() — that redirects import playwright... to Rustwright at runtime.
[!WARNING] Alpha. Chromium-only, built from source (PyPI/npm publishing is the top roadmap item). Need Firefox/WebKit or production maturity today? Use
playwright-python. Full list: Limitations.
What is Rustwright?
Rustwright is a browser automation library for Python and Node.js that keeps the Playwright API you already know but drives Chromium from a native Rust engine speaking raw Chrome DevTools Protocol — no driver subprocess in the path.
playwright-python: your code ──pipe──► Node driver (separate process) ──CDP──► Chromium
rustwright: your code ────────────────── raw CDP ─────────────────────► Chromium
Why Rustwright?
- No Node driver subprocess.
playwright-pythonlaunches and pipes to a bundled Node driver. Rustwright's engine is native — the browser-control code runs in-process. - Raw CDP, in Rust. A from-scratch async CDP client — not a wrapper around another automation library.
- No Playwright automation fingerprint. The driver never loads, so its signatures never appear. See Signal hygiene.
- Trusted input by default. Clicks and typing go through real CDP input events (
Input.dispatchMouseEvent), not syntheticelement.click()DOM calls. Untrusted DOM shortcuts are opt-in only. - Cross-origin iframes (OOPIF). Auto-attaches out-of-process iframe targets with flattened CDP sessions and routes
frame_locator()across origins. - One engine, two languages. The same Rust core backs the Python and Node bindings.
How it works
One Rust core — an async CDP client built on Tokio (WebSocket, with opt-in Unix-pipe transport) — talks to Chromium directly, and thin PyO3 (Python) and napi-rs (Node) bindings expose it in-process. The two-line diagram above is the entire architecture.
Install
No package is published yet — publishing to PyPI and npm is the top roadmap item; star or watch the repo to catch the release. Until then, Rustwright builds from source on Linux, macOS, and Windows with a Rust toolchain (1.85+).
Python (3.8+)
git clone https://github.com/Skyvern-AI/rustwright && cd rustwright
python -m venv .venv && source .venv/bin/activate
python -m pip install -U pip maturin
maturin develop --release # compiles the Rust engine (~5 min on first build)
python -m rustwright install chromium # fetch a Chromium build
Keep the virtual environment activated when running maturin develop — maturin can print a success message while installing nothing into a non-active environment. If import rustwright later raises ModuleNotFoundError, run source .venv/bin/activate and rerun maturin develop --release.
Node.js (experimental — contributors only for now)
cd rustwright/node
npm install
npm run build # builds the native addon via napi-rs
The build produces a local package; consume it from another project with npm install /path/to/rustwright/node (or npm link). Only a subset of the API surface is bridged — see Limitations.
Already have a Chromium/Chrome binary? Point Rustwright at it with RUSTWRIGHT_CHROMIUM, CHROME, or CHROMIUM.
Signal hygiene
Because Rustwright never loads Playwright's Node driver, it never emits the automation signatures that ship with it:
- No Playwright driver signatures — no
__playwright__binding__/ utility-world globals, no driver bootstrap. The backend reportsplaywright_driver: "none". - No
Runtime.enableon the default path — a normal launch + navigate never enables the CDP Runtime domain, closing theRuntime.enableconsole-serialization leak behindisAutomatedWithCDP. (Console/page-error/binding opt-ins still enable it lazily — detectable by design.) - Headless identity normalized by default — launches with
--disable-blink-features=AutomationControlled, rewritesHeadlessChrome/→Chrome/in the UA and client hints, and installs anavigator.webdrivercleanup init script.
Local fingerprint runs — default Playwright failed webdriver/headless checks that Rustwright passed; these are local diagnostics, not a guarantee:
| Probe | Result |
|---|---|
| SannySoft | ✅ Clean |
| BrowserScan | ✅ Clean |
| DeviceAndBrowserInfo | ✅ Clean (after the Runtime-domain cleanup) |
| CreepJS | ⚠️ Detects headless |
[!IMPORTANT] Rustwright is not "undetectable." It is not a CAPTCHA or Cloudflare bypass, and it is not fully CDP-invisible — it still uses CDP primitives (
Target.setAutoAttach, init scripts, and lazyRuntime.enablefor console event/pageerror event/binding opt-ins). The claim is narrow: no Playwright-specific automation fingerprint, plus baseline signal hygiene.
Benchmarks
Rustwright does not headline a speed number yet: launch-facing claims are held to reproducible, isolated CI evidence (Testbox + capped Docker), which is not yet published. Two diagnostic runs exist today — a local dev-host run where Rustwright won 16/17 case means, and a hosted strict run with a narrower gap:
| Run | Cases | Rustwright | playwright-python | Speedup |
|---|---|---|---|---|
| Local dev host (warm browser, 5 iterations) | 17 | 5,256 ms | 13,418 ms | 2.55× |
| Hosted strict run | 78 | — | — | ~1.37× |
Treat both as diagnostics, not launch claims — neither is capped-Docker/CI evidence. Methodology: BENCHMARK.md.
Rustwright vs the alternatives
| Rustwright | playwright-python | Puppeteer | Patchright | |
|---|---|---|---|---|
| API | Playwright-shaped (Py + Node) | Official Python Playwright | JS/TS Puppeteer | Playwright drop-in fork |
| Engine / transport | Rust core, raw CDP | Python → Node driver | Node over CDP | Patched PW driver |
| In-process engine (no driver subprocess) | ✅ | ❌ bundled Node driver | ✅ Node is the runtime | ❌ Playwright-style driver |
| Browsers | Chromium only | Chromium, Firefox, WebKit | Chrome, Firefox | Chromium-based |
| Default input | Trusted CDP events | Browser-level | Browser / CDP | Playwright + stealth |
| Cross-origin iframes | OOPIF (alpha) | Mature | Frame APIs | Inherits Playwright |
| Playwright fingerprint | No | Yes | n/a | Patched |
| Maturity | 🟠 Alpha | 🟢 Mature | 🟢 Mature | 🟡 Focused fork |
Rustwright's lane: a Rust CDP engine under the Playwright API, for Chromium.
Limitations
See LIMITATIONS.md for detail.
- Alpha — API shape covered; full behavioral parity not yet proven.
- Chromium only — Firefox and WebKit error explicitly.
- Node bindings are early — a subset of the surface is bridged (
launch,newPage,goto,click,fill,title,textContent,evaluate,screenshot,close); contexts, routing, tracing, and locators are Python-only for now. - Async concurrency (Python) — the async API wraps the sync engine via threads; recommended for ≈≤25 concurrent workflows/process, not high fan-out.
- OOPIF — residual gaps in non-main-frame
JSHandlefollow-ups and drag/screenshot/bounding-box. - Signal hygiene is partial — 3 of 4 public fingerprint targets clean in local runs (CreepJS still detects headless). No undetectability promise.
Roadmap
- Publish to PyPI and npm — top priority
- CI / Testbox-backed benchmark evidence
- Native async engine (remove the Python thread-pool bridge)
- Broaden the Node.js surface (contexts, routing, locators)
- Close remaining OOPIF gaps
- Split the core into maintainable modules
Recently shipped:
- OOPIF auto-attach with flattened CDP sessions
- 515/515 shared parity suite green against real Playwright
-
Runtime.enableconsole-serialization leak closed on the default path
Firefox and WebKit are not planned — Rustwright is deliberately Chromium-only.
Contributing
Rustwright is Rust + Python + Node. cargo builds the engine; maturin develop --release installs the Python package; cd node && npm run build builds the Node addon; the Python suite exercises the engine against real Chromium. Full Docker gate: 1,046 tests pass (6 skipped), plus 515/515 shared parity cases run against real Playwright; CI (test.yml) runs a fast representative subset on every PR.
See CONTRIBUTING.md for build details and the code-layout reality.
Project status
Rustwright is an early alpha from Skyvern, developed in the open. If the architecture resonates, give it a ⭐.
Questions, ideas, or want to help? Join the Skyvern community on Discord.
License
MIT © 2026 Ikonomos Inc (dba Skyvern)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rustwright-0.1.0a3.tar.gz.
File metadata
- Download URL: rustwright-0.1.0a3.tar.gz
- Upload date:
- Size: 2.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
917e09dab9454cda208a173a4d564242cc6f43ac0b9659fa7efe89472dd14319
|
|
| MD5 |
0e7d860975918d055d17a2f9939f0694
|
|
| BLAKE2b-256 |
6f2f3e2e0e60cc789ef15caeecbcdc80c28093aa76cb8ee44bcef178a3f48427
|
Provenance
The following attestation bundles were made for rustwright-0.1.0a3.tar.gz:
Publisher:
release-pypi.yml on Skyvern-AI/rustwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rustwright-0.1.0a3.tar.gz -
Subject digest:
917e09dab9454cda208a173a4d564242cc6f43ac0b9659fa7efe89472dd14319 - Sigstore transparency entry: 2165644035
- Sigstore integration time:
-
Permalink:
Skyvern-AI/rustwright@9be77da8d00cb82678133631f8b9987b20cc28ee -
Branch / Tag:
refs/tags/v0.1.0-alpha.3 - Owner: https://github.com/Skyvern-AI
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@9be77da8d00cb82678133631f8b9987b20cc28ee -
Trigger Event:
push
-
Statement type:
File details
Details for the file rustwright-0.1.0a3-cp38-abi3-win_amd64.whl.
File metadata
- Download URL: rustwright-0.1.0a3-cp38-abi3-win_amd64.whl
- Upload date:
- Size: 3.7 MB
- Tags: CPython 3.8+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d6809479a3f0bb73217f4f192d0637239e68a0787e12bfb7757528ae08979784
|
|
| MD5 |
dc0f39cca2ee217e34a1c29b2291278d
|
|
| BLAKE2b-256 |
ba6b99197762d29c71e796f7087739731c86829821db897e1b76e348f4bfefb0
|
Provenance
The following attestation bundles were made for rustwright-0.1.0a3-cp38-abi3-win_amd64.whl:
Publisher:
release-pypi.yml on Skyvern-AI/rustwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rustwright-0.1.0a3-cp38-abi3-win_amd64.whl -
Subject digest:
d6809479a3f0bb73217f4f192d0637239e68a0787e12bfb7757528ae08979784 - Sigstore transparency entry: 2165644065
- Sigstore integration time:
-
Permalink:
Skyvern-AI/rustwright@9be77da8d00cb82678133631f8b9987b20cc28ee -
Branch / Tag:
refs/tags/v0.1.0-alpha.3 - Owner: https://github.com/Skyvern-AI
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@9be77da8d00cb82678133631f8b9987b20cc28ee -
Trigger Event:
push
-
Statement type:
File details
Details for the file rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 4.0 MB
- Tags: CPython 3.8+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4b790c1b2cb4e167c70ec46434d506197d0d79d5520050d87dfeb361f03191f
|
|
| MD5 |
cf34eebdeaf54161c8dda7863ccfc7f1
|
|
| BLAKE2b-256 |
651e49bc5dafacf8b8734c1f3ea04e9897e717835fa096e3691916c8be61e6bc
|
Provenance
The following attestation bundles were made for rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release-pypi.yml on Skyvern-AI/rustwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
d4b790c1b2cb4e167c70ec46434d506197d0d79d5520050d87dfeb361f03191f - Sigstore transparency entry: 2165644056
- Sigstore integration time:
-
Permalink:
Skyvern-AI/rustwright@9be77da8d00cb82678133631f8b9987b20cc28ee -
Branch / Tag:
refs/tags/v0.1.0-alpha.3 - Owner: https://github.com/Skyvern-AI
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@9be77da8d00cb82678133631f8b9987b20cc28ee -
Trigger Event:
push
-
Statement type:
File details
Details for the file rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 3.4 MB
- Tags: CPython 3.8+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3dcce1a31da9f7c9f0897d73f161a6719cc231289ce07315d3ff03f7b88a2fe1
|
|
| MD5 |
66e09314d6d69e07186d8cdf7f8ba212
|
|
| BLAKE2b-256 |
d8c0cc07b5356e769d163e8c21a23e452a3f0b670e8e848cdd74c745c69962ff
|
Provenance
The following attestation bundles were made for rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release-pypi.yml on Skyvern-AI/rustwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
3dcce1a31da9f7c9f0897d73f161a6719cc231289ce07315d3ff03f7b88a2fe1 - Sigstore transparency entry: 2165644046
- Sigstore integration time:
-
Permalink:
Skyvern-AI/rustwright@9be77da8d00cb82678133631f8b9987b20cc28ee -
Branch / Tag:
refs/tags/v0.1.0-alpha.3 - Owner: https://github.com/Skyvern-AI
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@9be77da8d00cb82678133631f8b9987b20cc28ee -
Trigger Event:
push
-
Statement type:
File details
Details for the file rustwright-0.1.0a3-cp38-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: rustwright-0.1.0a3-cp38-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 3.6 MB
- Tags: CPython 3.8+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f4bab2472dd47f56e2d829f1e2c627050d03e3e1368a9098a88fdf6de1f64ba
|
|
| MD5 |
7923f474fce547d83898626f6739bc68
|
|
| BLAKE2b-256 |
43d6d436fa4768a433a20c48471ef3bf1c85ec6c5feadae5e7eb54a12057c224
|
Provenance
The following attestation bundles were made for rustwright-0.1.0a3-cp38-abi3-macosx_11_0_arm64.whl:
Publisher:
release-pypi.yml on Skyvern-AI/rustwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rustwright-0.1.0a3-cp38-abi3-macosx_11_0_arm64.whl -
Subject digest:
2f4bab2472dd47f56e2d829f1e2c627050d03e3e1368a9098a88fdf6de1f64ba - Sigstore transparency entry: 2165644083
- Sigstore integration time:
-
Permalink:
Skyvern-AI/rustwright@9be77da8d00cb82678133631f8b9987b20cc28ee -
Branch / Tag:
refs/tags/v0.1.0-alpha.3 - Owner: https://github.com/Skyvern-AI
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@9be77da8d00cb82678133631f8b9987b20cc28ee -
Trigger Event:
push
-
Statement type:
File details
Details for the file rustwright-0.1.0a3-cp38-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: rustwright-0.1.0a3-cp38-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 3.8 MB
- Tags: CPython 3.8+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
78160a7a752e9501b44f4df71e7e2613772e8a1e345c926ef731d57fbac916ed
|
|
| MD5 |
6843003a72e83bb5ea51fe03bb0b0aeb
|
|
| BLAKE2b-256 |
3d5a4455745057eb09d337822fc7fb60ff73a4b821d85a1d08a17beb1b1c3e0a
|
Provenance
The following attestation bundles were made for rustwright-0.1.0a3-cp38-abi3-macosx_10_12_x86_64.whl:
Publisher:
release-pypi.yml on Skyvern-AI/rustwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rustwright-0.1.0a3-cp38-abi3-macosx_10_12_x86_64.whl -
Subject digest:
78160a7a752e9501b44f4df71e7e2613772e8a1e345c926ef731d57fbac916ed - Sigstore transparency entry: 2165644076
- Sigstore integration time:
-
Permalink:
Skyvern-AI/rustwright@9be77da8d00cb82678133631f8b9987b20cc28ee -
Branch / Tag:
refs/tags/v0.1.0-alpha.3 - Owner: https://github.com/Skyvern-AI
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@9be77da8d00cb82678133631f8b9987b20cc28ee -
Trigger Event:
push
-
Statement type: