Skip to main content

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

Project description

Rustwright — a drop-in replacement for Playwright

A Rust rewrite of Playwright, a popular browser automation library. Rustwright is interoperable with Playwright but runs on an in-process Rust CDP engine — 2.55× faster and 70% less memory (no Node driver), with no Playwright automation fingerprint. Alpha; Chromium-only.

status: alpha tests license: MIT Python 3.8+ npm Chromium only Discord


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 ──CDP──► Chromium
rustwright:         your code ────────── raw CDP ──────────► Chromium

Quickstart

Rustwright is interoperable with Playwright — install it, change one import, and your existing code runs on the Rust engine.

Python

pip install rustwright
python -m rustwright install chromium
- 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 (experimental)

Install from npm:

npm install rustwright

The Node binding drives an existing Chromium/Chrome — point Rustwright at it with RUSTWRIGHT_CHROMIUM, CHROME, or CHROMIUM. Prefer to build from source? git clone the repo and run npm install && npm run build in node/.

- 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();

Only a subset of the API surface is bridged — see Limitations.

Why Rustwright?

Rustwright vs playwright-python live demo
  • 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 Automation detection.
  • 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.

Already have a Chromium/Chrome binary? Point Rustwright at it with RUSTWRIGHT_CHROMIUM, CHROME, or CHROMIUM.

Remote browsers (Skyvern)

Rustwright drives browsers — but you still need somewhere to run them. Skyvern (the team behind Rustwright) offers hosted Browser Sessions as a paid service that funds this project.

Features:

  • Persistent cloud browsers — logins, cookies, and tab state carry across runs
  • Configurable timeouts — 5 minutes to 24 hours (60 min default)
  • Proxies in 21 countries
  • Live view — watch and interact with the session in the Skyvern Cloud UI

Each session returns a browser_address CDP endpoint that Rustwright connects to like any remote Chromium (sessions bill while open).

Get started:

  1. Make an account at app.skyvern.com
  2. Grab your API key from Settings
  3. pip install skyvern
import asyncio
from rustwright.async_api import async_playwright
from skyvern import Skyvern

async def main():
    session = await Skyvern(api_key="<SKYVERN_API_KEY>").create_browser_session()

    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(session.browser_address)
        page = await browser.new_page()
        await page.goto("https://example.com")

asyncio.run(main())

Remote sessions are Python-only for now — Rustwright's Node binding doesn't support connect_over_cdp yet (it's on the Roadmap).

Automation detection

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

The headline numbers are local diagnostics, not yet capped-CI evidence. On speed, one dev-host run (warm browser, 5 iterations) won 16 of 17 case means:

Run Cases Rustwright playwright-python Speedup
Local dev host (warm browser, 5 iterations) 17 5,256 ms 13,418 ms 2.55×

Treat it as a diagnostic, not a launch claim — it is not capped-Docker/CI evidence. Methodology: BENCHMARK.md.

On memory, a form-fill diagnostic recorded the client library's footprint at 133.5 MiB for playwright-python (Python + Node driver) versus 40.6 MiB for Rustwright (no driver) — about 70% less; a separate async-concurrency diagnostic measured ~66% less on the same client-stack basis. Both cover the part the library controls — Chromium-dominated whole-process memory is roughly equal — and both are demo-grade diagnostics, not capped-CI evidence.

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.
  • API coverage — ~96% of Playwright's Python sync API (515 of 536 methods; 411 exercised by the shared parity registry); the async API provides 488 of 536. Full report: docs/PARITY.md.
  • 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.
  • Automation detection is partial — 3 of 4 public fingerprint targets clean in local runs (CreepJS still detects headless). No undetectability promise.

Roadmap

  • Language bindings — one Rust engine, many languages: Go, Java, Kotlin, C#/.NET, Ruby, and PHP (plus a native Rust API)
  • Rustwright MCP server — expose browser automation as tools for MCP-compatible AI agents
  • CI / Testbox-backed benchmark evidence
  • Broaden the Node.js surface (contexts, routing, locators)
  • Close remaining OOPIF gaps

Recently shipped:

  • Python package published to PyPI
  • Node.js binding published to npm
  • Native async engine over the Tokio CDP core
  • 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.1.tar.gz (3.8 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.1-cp38-abi3-win_amd64.whl (4.2 MB view details)

Uploaded CPython 3.8+Windows x86-64

rustwright-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.5 MB view details)

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

rustwright-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.9 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

rustwright-0.1.1-cp38-abi3-macosx_11_0_arm64.whl (4.1 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

rustwright-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl (4.3 MB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

Details for the file rustwright-0.1.1.tar.gz.

File metadata

  • Download URL: rustwright-0.1.1.tar.gz
  • Upload date:
  • Size: 3.8 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.1.tar.gz
Algorithm Hash digest
SHA256 9a42264eaa7c7aa1a11eaa81a34699e8b8c83a504bd6eb3c61a444c242a5b98d
MD5 3e1ff505b2c505aeb875c62d57f33b15
BLAKE2b-256 5180c4b1fe7f942b8fbbf0420295cb265413bb6ad874d2064a53e95782c7d8c5

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: rustwright-0.1.1-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 4.2 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.1-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 fc44f2be7918c98fd444522848d506786cb35b4e2e02a9efc722734f4e700458
MD5 b1b3df5985f94913d87e1233ffcc563f
BLAKE2b-256 607447ee2c9f924fa25b522826a5761a1b0e362789d9f668f51f09cab784a03c

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustwright-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4c9bd1a72db79fbfaf20ba829a74564e8a82088ae8a939daff1cf3c9c3e7f8cd
MD5 b11b8e98011bba90b18b676d243215bb
BLAKE2b-256 ffa19e1b3224e9a2c82e7b44d9abbb00a0e65e6b7ff40a5cfa6832f783330051

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustwright-0.1.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ddc60409aa12478c9617b742356be7f5baae81b17e77dabfbe040fc43864fa4e
MD5 ba3024ad518bd342e51e495ec46c4c10
BLAKE2b-256 f4cb4d8714e27ba6ea0a430f96a1baf3b09c56a75d2920a467bb44d03cf95bca

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustwright-0.1.1-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 01f969f691acb2b61f830c32e2b23c97c59a108b661086bde58652d84821841f
MD5 1d0ab52cd2eaf85b6eef6082f6f8fa1d
BLAKE2b-256 b9523ccddd9f1e5436e543149b16c5f50bf9fd5fab27fcf7be7a7f8e9b795931

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for rustwright-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 fcfb8afc5ec10146727d7d57b66528022a37fd9bc2408c25dcdc72868521e131
MD5 f157180aed4fc2c2f4288167b043c25e
BLAKE2b-256 b3ea878236a78cd0da88a629471501b01b5aef92eecce438b0e6ab8de670199f

See more details on using hashes here.

Provenance

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