Skip to content

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:

BucketExamplesWhat happens
Action methodsgoto, click, fill, waitForSelector, evaluate, screenshot, …Logged with timing, wrapped in try/catch for error capture
Proxy-returning methodslocator, getByRole, getByText, first, nth, filter, …Return proxied children, so capture follows chained locators
Everything elseproperties, sync helpersPassthrough 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 matches password, 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() and browser.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’s PageObserver for manual snapshots or diagnostics.
  • Playwright type re-exportsBrowser, Page, Locator, LaunchOptions, and the rest are re-exported, so @autowright/browser can be your only browser import.

For the full config surface, see Configuration.