Skip to main content

A Rust-backed, CDP-first Python automation library with a Playwright-compatible sync API

Project description

Rustwright — Keep the Playwright API. Drop the driver.

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.

status: alpha tests license: MIT Python 3.8+ Node.js Chromium only Discord


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-python launches 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 synthetic element.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 reports playwright_driver: "none".
  • No Runtime.enable on the default path — a normal launch + navigate never enables the CDP Runtime domain, closing the Runtime.enable console-serialization leak behind isAutomatedWithCDP. (Console/page-error/binding opt-ins still enable it lazily — detectable by design.)
  • Headless identity normalized by default — launches with --disable-blink-features=AutomationControlled, rewrites HeadlessChrome/Chrome/ in the UA and client hints, and installs a navigator.webdriver cleanup 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 lazy Runtime.enable for 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 JSHandle follow-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.enable console-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)

Built with 🦀🐉 and a lot of CDP frames · Skyvern-AI/rustwright

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rustwright-0.1.0a3.tar.gz (2.7 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rustwright-0.1.0a3-cp38-abi3-win_amd64.whl (3.7 MB view details)

Uploaded CPython 3.8+Windows x86-64

rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.0 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ x86-64

rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

rustwright-0.1.0a3-cp38-abi3-macosx_11_0_arm64.whl (3.6 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

rustwright-0.1.0a3-cp38-abi3-macosx_10_12_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

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

Hashes for rustwright-0.1.0a3.tar.gz
Algorithm Hash digest
SHA256 917e09dab9454cda208a173a4d564242cc6f43ac0b9659fa7efe89472dd14319
MD5 0e7d860975918d055d17a2f9939f0694
BLAKE2b-256 6f2f3e2e0e60cc789ef15caeecbcdc80c28093aa76cb8ee44bcef178a3f48427

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustwright-0.1.0a3.tar.gz:

Publisher: release-pypi.yml on Skyvern-AI/rustwright

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for rustwright-0.1.0a3-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 d6809479a3f0bb73217f4f192d0637239e68a0787e12bfb7757528ae08979784
MD5 dc0f39cca2ee217e34a1c29b2291278d
BLAKE2b-256 ba6b99197762d29c71e796f7087739731c86829821db897e1b76e348f4bfefb0

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d4b790c1b2cb4e167c70ec46434d506197d0d79d5520050d87dfeb361f03191f
MD5 cf34eebdeaf54161c8dda7863ccfc7f1
BLAKE2b-256 651e49bc5dafacf8b8734c1f3ea04e9897e717835fa096e3691916c8be61e6bc

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for rustwright-0.1.0a3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3dcce1a31da9f7c9f0897d73f161a6719cc231289ce07315d3ff03f7b88a2fe1
MD5 66e09314d6d69e07186d8cdf7f8ba212
BLAKE2b-256 d8c0cc07b5356e769d163e8c21a23e452a3f0b670e8e848cdd74c745c69962ff

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustwright-0.1.0a3-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rustwright-0.1.0a3-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2f4bab2472dd47f56e2d829f1e2c627050d03e3e1368a9098a88fdf6de1f64ba
MD5 7923f474fce547d83898626f6739bc68
BLAKE2b-256 43d6d436fa4768a433a20c48471ef3bf1c85ec6c5feadae5e7eb54a12057c224

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rustwright-0.1.0a3-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for rustwright-0.1.0a3-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 78160a7a752e9501b44f4df71e7e2613772e8a1e345c926ef731d57fbac916ed
MD5 6843003a72e83bb5ea51fe03bb0b0aeb
BLAKE2b-256 3d5a4455745057eb09d337822fc7fb60ff73a4b821d85a1d08a17beb1b1c3e0a

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page