跪拜 Guibai
← All articles
JavaScript

Bun Ships a Zero-Dependency WebView That Screenshots in 3 Lines

By 半刻纬度 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Browser automation has been a heavyweight dependency for years. A built-in, zero-install WebView inside the runtime shrinks the cost of screenshot generation, scraping, and integration testing to a few lines of script — no driver, no separate browser binary, no system packages.

Summary

Bun.WebView eliminates the 300 MB Chromium download and system-library dance that comes with Puppeteer. On macOS it uses the built-in WKWebView; on Linux and Windows it auto-discovers an existing Chrome, Edge, or Chromium installation. A screenshot takes three lines of code, and the API returns a raw Buffer that can be written to disk or piped anywhere.

Beyond screenshots, the API dispatches genuine OS-level keyboard and mouse events — `isTrusted` is always true — so anti-bot detection sees real interaction. `evaluate` runs arbitrary JavaScript in the page context and returns JSON-serializable values, with Promises automatically awaited. Multiple views share a single browser subprocess, making crawls faster than launching a fresh browser each time.

Persistence is a one-liner via `dataStore`, which saves cookies and localStorage to a directory. Console output from the page is captured through a callback, and raw Chrome DevTools Protocol commands are available for network interception, performance tracing, or cookie manipulation. The feature is experimental and requires Bun ≥ 1.3.12; temporary directories are cleaned up automatically when `await using` is used.

Takeaways
Screenshots require only `new Bun.WebView()`, `navigate`, and `screenshot()` — three lines total.
On macOS the API uses the system WKWebView with zero configuration; on Linux/Windows it auto-discovers Chrome, Edge, or Chromium.
`click`, `type`, and `press` dispatch real OS-level events, so `isTrusted` is true and anti-bot defenses cannot distinguish them from human input.
`evaluate` runs JavaScript inside the page and returns JSON-serializable values, automatically awaiting Promises.
Multiple `WebView` instances share a single browser subprocess, making crawls faster than launching a new browser each time.
Login state persists across runs by passing a `dataStore` directory — cookies and localStorage are saved to disk.
Page console output is captured through a `console` callback, and raw CDP commands are supported for network interception and performance monitoring.
The feature is experimental in Bun ≥ 1.3.12; temporary directories are auto-cleaned when `await using` is used.
Conclusions

Bun is absorbing use cases that previously required a separate automation library, turning the runtime itself into a browser driver.

Using the OS-native WebView on macOS sidesteps the entire Chromium dependency chain, which is the single largest source of friction in headless browsing.

Dispatching OS-level events rather than synthetic DOM events closes a long-standing gap between scripted automation and what websites actually see, making bot detection far harder.

The shared subprocess model — one browser, many views — is a practical performance win that Playwright and Puppeteer could adopt more aggressively.

Exposing CDP directly alongside a high-level API gives developers an escape hatch without pulling in another library, which keeps the dependency tree small.

Concepts & terms
WKWebView
Apple's built-in web rendering engine on macOS and iOS, used by Safari and now by Bun.WebView to avoid downloading Chromium.
CDP (Chrome DevTools Protocol)
The low-level protocol that Chrome exposes for debugging, network interception, performance profiling, and DOM inspection. Bun.WebView lets you send raw CDP commands and subscribe to events.
isTrusted
A read-only property on DOM events that is `true` only when the event was generated by a real user action, not by JavaScript. Bun.WebView's OS-level events set this to `true`, defeating many bot-detection scripts.
await using
A TC39 Stage 3 proposal for explicit resource management. It automatically calls a disposable object's cleanup method when the block exits, similar to Python's `with` statement or C#'s `using`.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗