ChromeWebView
ChromeWebView is the main public class exported by webotron.
Import
Section titled “Import”import { ChromeWebView } from "webotron";Constructor
Section titled “Constructor”const view = new ChromeWebView(options);ChromeWebViewOptions
Section titled “ChromeWebViewOptions”| Option | Type | Default | Notes |
|---|---|---|---|
chromePath | string | system Chrome | Path to Chrome/Chromium executable. |
headless | boolean | false | Runs with visible window by default. |
windowSize | { width: number; height: number } | { width: 1280, height: 800 } | Initial emulated viewport/window size. |
userDataDir | string | resolved profile path | Optional explicit browser profile path. |
profile | ChromeProfileOptions | shared temp profile | Controls whether the browser uses a stable shared temp profile or an isolated ephemeral one. |
initialUrl | string | "" | Optional first URL to open during startup. |
appMode | boolean | false | Enables app-style launch behavior. |
argv | string | string[] | ChromeArgvMutator | undefined | Adds or rewrites Chrome launch arguments before the browser process starts. |
attach | ChromeAttachOptions | undefined | Connect to an existing browser/target instead of launching a new instance. |
Attach mode requirements
Section titled “Attach mode requirements”When attach is provided, at least one of these must be set:
attach.pageWSEndpointattach.browserWSEndpointattach.devToolsPort
If none are provided, constructor throws.
Custom Chrome arguments
Section titled “Custom Chrome arguments”Use argv when you need to add extra Chrome flags at launch time.
- Pass a
stringto add one flag. - Pass a
string[]to add multiple flags. - Pass a function when you want to inspect or rewrite the full generated argv list.
const view = new ChromeWebView({ chromePath, argv: ["--disable-gpu", "--lang=en-US"],});const view = new ChromeWebView({ chromePath, argv: (argv) => { argv.push("--disable-gpu"); return [...argv, "--lang=en-US"]; },});Be careful with flags that overlap with arguments managed by ChromeWebView, such as profile or remote debugging flags.
Browser profile behavior
Section titled “Browser profile behavior”When you do not provide userDataDir, ChromeWebView now uses a stable shared temp profile directory by default.
- Default behavior: shared temp profile at
.../webotron-chrome-profile - Isolated behavior: generate a unique temp profile for that instance
- Isolated cleanup default: generated isolated profiles are removed on
close() - Optional opt-out: set
cleanupEphemeral: falseto keep an isolated generated profile afterclose()
const view = new ChromeWebView({ profile: { isolation: "isolated", },});If you provide userDataDir, that path always wins and the profile helper options are ignored.
Public state fields
Section titled “Public state fields”| Field | Type | Meaning |
|---|---|---|
loading | boolean | Current navigation loading state. |
title | string | Last known page title. |
url | string | Last known page URL. |
onNavigated | ((url: string, title: string) => void) | null | Optional callback fired on successful navigation updates. |
onNavigationFailed | ((error: Error) => void) | null | Optional callback fired when navigation fails. |
Navigation callbacks
Section titled “Navigation callbacks”Set onNavigated and onNavigationFailed when you want to observe navigations globally instead of only awaiting explicit navigation calls.
onNavigated is fired for:
navigate()reload()goBack()goForward()- page-triggered navigations such as link clicks
- script-triggered navigations such as
location.href = ... - redirects that commit in the main frame
onNavigationFailed is fired for:
- explicit navigation command failures
- main-frame document navigation failures detected from the network layer
These callbacks are intended for observation. If you need precise control over when an explicit navigation promise resolves, use the waitUntil and timeoutMs options on the navigation method itself.
API coverage
Section titled “API coverage”CDP and events
Section titled “CDP and events”| Member | Signature | Description |
|---|---|---|
cdp | cdp(method: string, params?: Record<string, unknown>): Promise<any> | Sends a raw CDP command after readiness checks. |
addEventListener | addEventListener(type, listener, options?) | Subscribes to CDP event names through an EventTarget-compatible adapter. |
removeEventListener | removeEventListener(type, listener) | Removes event listener subscriptions. |
dispatchEvent | dispatchEvent(event): boolean | Dispatches events through the same adapter. |
Navigation
Section titled “Navigation”| Member | Signature | Description |
|---|---|---|
navigate | navigate(url: string, options?: NavigateOptions): Promise<void> | Navigates current target to a URL and waits for the requested navigation milestone. |
goBack | goBack(options?: NavigateOptions): Promise<void> | Browser history back with the same navigation wait options as navigate(). |
goForward | goForward(options?: NavigateOptions): Promise<void> | Browser history forward with the same navigation wait options as navigate(). |
reload | reload(options?: NavigateOptions): Promise<void> | Reloads current document with the same navigation wait options as navigate(). |
waitForDocumentReady | waitForDocumentReady(options?: WaitForDocumentReadyOptions): Promise<void> | Waits for interactive or complete ready state. |
DOM and waiting
Section titled “DOM and waiting”| Member | Signature | Description |
|---|---|---|
getElementById | getElementById(id: string): Promise<ElementHandle | null> | Gets an element reference by DOM id. |
querySelector | querySelector(selector: string): Promise<ElementHandle | null> | Gets an element reference from a CSS selector. |
getFrame | getFrame(selector: string): Promise<FrameLocator | null> | Gets a chainable frame locator for the matched frame or iframe element. |
getFrameElement | getFrameElement(selector: string): Promise<ElementHandle | null> | Gets the underlying frame or iframe element reference. |
getByRole | getByRole(role: string, options?: RoleLocatorOptions): Promise<ElementHandle | null> | Finds an element by accessible role and optional name. |
getByText | getByText(text: string, options?: LocatorMatchOptions): Promise<ElementHandle | null> | Finds an element by visible text content. |
getByLabel | getByLabel(label: string, options?: LocatorMatchOptions): Promise<ElementHandle | null> | Finds a form control by label text. |
getByPlaceholder | getByPlaceholder(text: string, options?: LocatorMatchOptions): Promise<ElementHandle | null> | Finds an input or textarea by placeholder text. |
getByAltText | getByAltText(text: string, options?: LocatorMatchOptions): Promise<ElementHandle | null> | Finds an image-like element by alt text. |
getByTitle | getByTitle(text: string, options?: LocatorMatchOptions): Promise<ElementHandle | null> | Finds an element by title attribute. |
getByDataAttribute | getByDataAttribute(name: string, value: string, options?: LocatorMatchOptions): Promise<ElementHandle | null> | Finds an element by data-* attribute. |
getByXPath | getByXPath(xpath: string): Promise<ElementHandle | null> | Finds the first element matched by an XPath expression. |
querySelectorAll | querySelectorAll(selector: string): Promise<ElementHandle[]> | Gets all matching element references from a CSS selector. |
querySelectorWithin | querySelectorWithin(parent: ElementHandle, selector: string): Promise<ElementHandle | null> | Runs a scoped query inside an existing element reference. |
querySelectorAllWithin | querySelectorAllWithin(parent: ElementHandle, selector: string): Promise<ElementHandle[]> | Runs a scoped query that returns all matches inside an existing element reference. |
getAttribute | getAttribute(target: ElementHandle, name: string): Promise<string | null> | Reads an attribute from an element reference. |
disposeElement | disposeElement(target: ElementHandle): Promise<void> | Disposes a stored element reference in the page bridge. |
waitForElement | waitForElement(selector: string, options?: WaitForElementOptions): Promise<boolean> | Waits for selector using observer or polling strategy. |
getElementBounds | getElementBounds(target: string | ElementHandle, timeoutMs?: number): Promise<ElementBounds> | Resolves element bounds by selector or reference. |
getElementCenter | getElementCenter(target: string | ElementHandle, options?: ElementPointOptions): Promise<{ x: number; y: number }> | Resolves clickable center point by selector or reference. |
findEditableClickTarget | findEditableClickTarget(): Promise<ClickTarget> | Finds best editable element target and click point. |
clickEditableTarget | clickEditableTarget(): Promise<ClickTarget> | Clicks editable target and returns point metadata. |
getActiveElementState | getActiveElementState(): Promise<{ tag: string; isEditable: boolean; value: string | null; text: string | null }> | Returns active element editability/value snapshot. |
Evaluation
Section titled “Evaluation”| Member | Signature | Description |
|---|---|---|
evaluate | evaluate<T = unknown>(script: string, options?: EvaluateOptions): Promise<T> | Evaluates JavaScript in page context with queued/non-blocking mode support. |
| Member | Signature | Description |
|---|---|---|
type | type(text: string, options?: TypeOptions): Promise<void> | Types text into focused element with optional per-character delay. |
click | click(selector: string, options?: ClickSelectorOptions): Promise<void> | Clicks selector-resolved point. |
click | click(target: ElementHandle, options?: ClickSelectorOptions): Promise<void> | Clicks an existing element reference. |
click | click(x: number, y: number, options?: ClickOptions): Promise<void> | Clicks explicit viewport coordinates. |
clickAt | clickAt(x: number, y: number): Promise<void> | Direct coordinate click helper. |
press | press(key: string, options?: PressOptions): Promise<void> | Sends key press with modifier support. |
resize | resize(width: number, height: number): Promise<void> | Updates browser viewport size. |
scroll | scroll(dx: number, dy: number): Promise<void> | Scrolls by delta values. |
scrollTo | scrollTo(selector: string, options?: ScrollToOptions): Promise<void> | Scrolls element into view by selector. |
Screenshot and capture
Section titled “Screenshot and capture”| Member | Signature | Description |
|---|---|---|
screenshot | screenshot(options?: ScreenshotOptions): Promise<Blob | Uint8Array | string | { name: string; size: number }> | General screenshot API with multiple output encodings. |
captureViewport | captureViewport(options?: ScreenshotOptions): Promise<Blob | Uint8Array | string> | Captures full viewport. |
captureElement | captureElement(selector: string, options?: ScreenshotOptions): Promise<Blob | Uint8Array | string> | Captures a selector-bounded region. |
captureRegion | captureRegion(x: number, y: number, width: number, height: number, options?: ScreenshotOptions): Promise<Blob | Uint8Array | string> | Captures an explicit rectangle. |
Lifecycle and disposal
Section titled “Lifecycle and disposal”| Member | Signature | Description |
|---|---|---|
getProcessId | getProcessId(): number | Returns attached process ID (if provided) or spawned Chrome PID. |
close | close(): Promise<void> | Idempotent shutdown: rejects pending CDP calls, closes socket, and kills owned process. |
closeAll | static closeAll(): void | Closes all tracked ChromeWebView instances. |
[Symbol.dispose] | [Symbol.dispose](): void | Sync dispose hook that initiates close. |
[Symbol.asyncDispose] | [Symbol.asyncDispose](): Promise<void> | Async dispose hook that awaits close completion. |
Minimal example
Section titled “Minimal example”import { ChromeWebView } from "webotron";
const view = new ChromeWebView({ headless: false, windowSize: { width: 1440, height: 900 },});
await view.navigate("https://example.com");await view.waitForDocumentReady({ state: "complete", timeoutMs: 15000 });await view.waitForElement("h1", { strategy: "observer", timeoutMs: 5000 });
const title = await view.evaluate<string>("document.title");console.log(title);
await view.close();Navigation wait modes
Section titled “Navigation wait modes”navigate() now accepts NavigateOptions so you can choose what “ready” means for a given page:
load: Best default for normal HTML pages when you want the browserloadevent.domcontentloaded: Useful when you only need parsed DOM and want to continue before all subresources finish.frameNavigated: Useful when you only need the top-level navigation to commit. This is a good fit for unusual documents such as streaming responses.responseReceived: Useful when you want to know the server has responded, even if page lifecycle events may never complete.eventSourceMessageReceived: Useful for pages that create anEventSourceconnection and where you want to wait for the first SSE message.
Limitations
Section titled “Limitations”loadanddomcontentloadedare page lifecycle milestones, so they may never fire for top-level streaming responses such astext/event-stream.frameNavigatedandresponseReceivedare earlier signals than DOM readiness. They confirm navigation commit or HTTP response, not that the page is interactive.eventSourceMessageReceivedis for in-pageEventSourcerequests. It is not a general signal for navigating the main frame directly to an SSE URL.
Element handle example
Section titled “Element handle example”import { ChromeWebView } from "webotron";
const view = new ChromeWebView({ headless: false });
await view.navigate("https://example.com");await view.waitForDocumentReady({ state: "complete" });
const container = await view.getElementById("content");if (!container) throw new Error("content container not found");
const button = await view.querySelectorWithin(container, "button.primary");if (!button) throw new Error("button not found");
const bounds = await view.getElementBounds(button);console.log("button bounds", bounds);
await view.click(button);await view.disposeElement(button);await view.disposeElement(container);
await view.close();Frame locator example
Section titled “Frame locator example”import { ChromeWebView } from "webotron";
const view = new ChromeWebView({ headless: false });
await view.navigate("https://example.com");await view.waitForDocumentReady({ state: "complete" });
const frame = await view.getFrame("iframe#payment-frame");if (!frame) throw new Error("payment frame not found");
const payButton = await frame.getByRole("button", { name: "Pay now" });if (!payButton) throw new Error("pay button not found");
await view.click(payButton);await view.close();