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.0a4.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.0a4-cp38-abi3-win_amd64.whl (3.7 MB view details)

Uploaded CPython 3.8+Windows x86-64

rustwright-0.1.0a4-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.0a4-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.0a4-cp38-abi3-macosx_11_0_arm64.whl (3.6 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

rustwright-0.1.0a4-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.0a4.tar.gz.

File metadata

  • Download URL: rustwright-0.1.0a4.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.0a4.tar.gz
Algorithm Hash digest
SHA256 84c1bb987db13ccafaf9f8770ffa66a6d74b96a05f430f05611ab4305db5b784
MD5 93816d5d3a13de403a891994a2e0878e
BLAKE2b-256 61914471c1cae7b72d6ee27392f42f1b6730ae195aae4d329085f63071b44a09

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustwright-0.1.0a4.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.0a4-cp38-abi3-win_amd64.whl.

File metadata

  • Download URL: rustwright-0.1.0a4-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.0a4-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 dfcec993319cb813ecada4fc024226893925aed07cc76e21955b318ab40963ca
MD5 c542a96cad0191db8dc4114640247c66
BLAKE2b-256 93207fb374f932f1df92ad12faaeba2a6b6cfe822422cf172d776dd08003be31

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustwright-0.1.0a4-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.0a4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rustwright-0.1.0a4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6eafa7f794a5f467e7883633f08c4593a342341f827da0c3fa3f9cc8337372ab
MD5 cf230617fcfbe0fd3dcc9e2e59154fb0
BLAKE2b-256 a8c17a37048b41e7a32a37c2b1a1cbf9ef01bae049d2c66c43b56e4392035623

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustwright-0.1.0a4-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.0a4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for rustwright-0.1.0a4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ffda8515232c33ba140424e50bb03a93db5e352f36fbef931cfc7944e596e94b
MD5 b7ede2a3a25091bd1d9d83b429fcc810
BLAKE2b-256 320ee6d83fa7bf205cda953082cc5d5ae5fb9512a24b2c9ca47ec59ced89046e

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustwright-0.1.0a4-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.0a4-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rustwright-0.1.0a4-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 59468b0c4b73a95af2ac754a956bd14f6307ed40849fc21006751357c9994b8c
MD5 85d0eec1f2d5c36f216e6f1df8ca3e35
BLAKE2b-256 6794e307e1c0715b04934a47d4393cfad81a255d713c6b6ddc63e2ca07bdbf2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustwright-0.1.0a4-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.0a4-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for rustwright-0.1.0a4-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 2182666059cb36488fe5bac38e5b8fe51af0a317d944deed4799cbfe40fe37a5
MD5 b55f76363c1a31cce21cbbc6bdf2b1d6
BLAKE2b-256 4fb36564841fa159d155b6cfe51593d70078936518b60fcbf0edb3cb63d080e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for rustwright-0.1.0a4-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