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

Uploaded CPython 3.8+Windows x86-64

rustwright-0.1.0a2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

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

rustwright-0.1.0a2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.3 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

rustwright-0.1.0a2-cp38-abi3-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

rustwright-0.1.0a2-cp38-abi3-macosx_10_12_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

Details for the file rustwright-0.1.0a2.tar.gz.

File metadata

  • Download URL: rustwright-0.1.0a2.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.0a2.tar.gz
Algorithm Hash digest
SHA256 51fb14f7bff4b9883a02b2c61dd9f625b860e67d02a28719a61f44c046c249c7
MD5 c171947ac9665df671bee15c11cb7abb
BLAKE2b-256 182db7d9ee68d1b33188ec4bc9212b00eb17950fd9d7c99797e2bbec6c3c7aa2

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: rustwright-0.1.0a2-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 3.5 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.0a2-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 6321204708ffb7237c1445b8919f12d838ae1337205ff69cd9a666a1dcd433d8
MD5 8a66210b98ab8ef010c729a140460bf4
BLAKE2b-256 bb776de4ff19616fe6aeec956fcd92f0655187b52e293391f49bc2e6a2b20b51

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustwright-0.1.0a2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2cfb2309ef71aec04c7704cf4ef603c5d5a507b2da00bc0d79d7b1ab95bb17a1
MD5 90e6e72e318aa28ab207a6551a3de96e
BLAKE2b-256 35dbd26cbb6603a07b68f11fa740ebfd2b85d4c74c06567ce9af34d464021e5d

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustwright-0.1.0a2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e6bb4b48870ebff8e32d32d8b62b253a161fcadcb679c69318b2f8440088740d
MD5 b03ffdb541ec6c42ddd68d21c2ee0960
BLAKE2b-256 78c596baf053b8601a6ec006f481dc5c843ab76d782b7688523188dd4b29c80f

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustwright-0.1.0a2-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fb6d8e1e2805f8f5fae8f0c87f7c75059d7c6593f608f2e408122a215e650253
MD5 593d0a8ad86e53c8ff93227e8ff4ea65
BLAKE2b-256 c57205cae7928bf829e46b1c66589d3006818c7bf835a43bca7acb449d901b1e

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustwright-0.1.0a2-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 9112b20b5a2ef71f6f25cec73d3818e884189bd1f4629309cc991b1d7d7b004d
MD5 25c79daa8424b4f25c5e6125d64c62d4
BLAKE2b-256 441906df50e2021cf3687091a9f8ce4d279afcacdd2f004ae839c31d04cb221e

See more details on using hashes here.

Provenance

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