Browser Package
@autowright/browser is the only piece of Autowright that lives in your code.
It ships a drop-in chromium whose launch() accepts the standard Playwright
options plus one autowright block — everything else is real Playwright.
import { chromium } from '@autowright/browser';
const browser = await chromium.launch({ headless: true, autowright: { scriptId: 'portal-scraper' },});scriptId and serviceUrl can also come from the environment
(AUTOWRIGHT_SCRIPT_ID, AUTOWRIGHT_SERVICE_URL), so a fleet of scripts can
share one config. On launch the script registers with the service —
best-effort and non-fatal: Autowright never refuses to launch if the
service is unreachable.
The transparent proxy
browser.newPage() returns a JS Proxy around the real Playwright Page. It
is a Page — same type, same methods, same behavior. The proxy sorts
method calls into three buckets:
| Bucket | Examples | What happens |
|---|---|---|
| Action methods | goto, click, fill, waitForSelector, evaluate, screenshot, … | Logged with timing, wrapped in try/catch for error capture |
| Proxy-returning methods | locator, getByRole, getByText, first, nth, filter, … | Return proxied children, so capture follows chained locators |
| Everything else | properties, sync helpers | Passthrough with correct this binding |
Locators get the same treatment: page.locator('#btn').click() is captured as
locator.click with its selector. The wrapping uses only the public
Playwright API plus Proxy — zero coupling to Playwright internals.
The PageObserver
Every wrapped page gets a PageObserver that listens to standard page events
and keeps rolling buffers sized for long-running scripts:
- Actions — last 1,000 intercepted calls with params and durations
- Network — last 500 request/response pairs with timings
- Console — last 500 page console messages
- Screenshots — the last 3, refreshed as the script runs
- Health — periodic page-liveness probes plus CPU/memory readings, and crash detection
Buffers drop the oldest entries first — the most recent activity is what a fix needs.
Credential redaction
Capture is designed to be safe to store:
fill()/type()values are replaced with[REDACTED]in the action log when the selector matchespassword,secret,token,key,credential, or[type="password"].- Sensitive keys (
password,token,secret,authorization,cookie,session) are stripped from captured params and network entries.
What happens on failure
When an intercepted call throws, the error is recorded with its duration, a
final DOM snapshot and screenshot are captured, the error is
classified, and artifacts are written to
local disk, bundled, and uploaded to storage (see
Artifacts). A lightweight ErrorContext — never the
artifact bytes — is POSTed to the service, and the original error is
re-thrown to your script.
Two more capture points cover errors that don’t surface as a throw:
page.close()andbrowser.close()capture a final DOM snapshot and screenshot before closing — so evidence survives even when your own error handling shuts the browser down.reportError()lets your application report failures the proxy can’t see, like a login that “succeeds” into an error page:
import { reportError } from '@autowright/browser';
try { await scraper.run();} catch (error) { if (error instanceof LoginCredentialsError) { await reportError(page, error, 'CREDENTIALS_INVALID', { currentStep: 'login', }); } await browser.close();}The classification argument is optional — omit it and Autowright classifies from the error and observer state. Call it before closing the browser so the snapshot can still be taken.
Escape hatches
getObserver(page)returns the page’sPageObserverfor manual snapshots or diagnostics.- Playwright type re-exports —
Browser,Page,Locator,LaunchOptions, and the rest are re-exported, so@autowright/browsercan be your only browser import.
For the full config surface, see Configuration.