Skip to content

ChromeWebView

ChromeWebView is the main public class exported by webotron.

import { ChromeWebView } from "webotron";
const view = new ChromeWebView(options);
OptionTypeDefaultNotes
chromePathstringsystem ChromePath to Chrome/Chromium executable.
headlessbooleanfalseRuns with visible window by default.
windowSize{ width: number; height: number }{ width: 1280, height: 800 }Initial emulated viewport/window size.
userDataDirstringresolved profile pathOptional explicit browser profile path.
profileChromeProfileOptionsshared temp profileControls whether the browser uses a stable shared temp profile or an isolated ephemeral one.
initialUrlstring""Optional first URL to open during startup.
appModebooleanfalseEnables app-style launch behavior.
argvstring | string[] | ChromeArgvMutatorundefinedAdds or rewrites Chrome launch arguments before the browser process starts.
attachChromeAttachOptionsundefinedConnect to an existing browser/target instead of launching a new instance.

When attach is provided, at least one of these must be set:

  • attach.pageWSEndpoint
  • attach.browserWSEndpoint
  • attach.devToolsPort

If none are provided, constructor throws.

Use argv when you need to add extra Chrome flags at launch time.

  • Pass a string to 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.

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: false to keep an isolated generated profile after close()
const view = new ChromeWebView({
profile: {
isolation: "isolated",
},
});

If you provide userDataDir, that path always wins and the profile helper options are ignored.

FieldTypeMeaning
loadingbooleanCurrent navigation loading state.
titlestringLast known page title.
urlstringLast known page URL.
onNavigated((url: string, title: string) => void) | nullOptional callback fired on successful navigation updates.
onNavigationFailed((error: Error) => void) | nullOptional callback fired when navigation fails.

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.

MemberSignatureDescription
cdpcdp(method: string, params?: Record<string, unknown>): Promise<any>Sends a raw CDP command after readiness checks.
addEventListeneraddEventListener(type, listener, options?)Subscribes to CDP event names through an EventTarget-compatible adapter.
removeEventListenerremoveEventListener(type, listener)Removes event listener subscriptions.
dispatchEventdispatchEvent(event): booleanDispatches events through the same adapter.
MemberSignatureDescription
navigatenavigate(url: string, options?: NavigateOptions): Promise<void>Navigates current target to a URL and waits for the requested navigation milestone.
goBackgoBack(options?: NavigateOptions): Promise<void>Browser history back with the same navigation wait options as navigate().
goForwardgoForward(options?: NavigateOptions): Promise<void>Browser history forward with the same navigation wait options as navigate().
reloadreload(options?: NavigateOptions): Promise<void>Reloads current document with the same navigation wait options as navigate().
waitForDocumentReadywaitForDocumentReady(options?: WaitForDocumentReadyOptions): Promise<void>Waits for interactive or complete ready state.
MemberSignatureDescription
getElementByIdgetElementById(id: string): Promise<ElementHandle | null>Gets an element reference by DOM id.
querySelectorquerySelector(selector: string): Promise<ElementHandle | null>Gets an element reference from a CSS selector.
getFramegetFrame(selector: string): Promise<FrameLocator | null>Gets a chainable frame locator for the matched frame or iframe element.
getFrameElementgetFrameElement(selector: string): Promise<ElementHandle | null>Gets the underlying frame or iframe element reference.
getByRolegetByRole(role: string, options?: RoleLocatorOptions): Promise<ElementHandle | null>Finds an element by accessible role and optional name.
getByTextgetByText(text: string, options?: LocatorMatchOptions): Promise<ElementHandle | null>Finds an element by visible text content.
getByLabelgetByLabel(label: string, options?: LocatorMatchOptions): Promise<ElementHandle | null>Finds a form control by label text.
getByPlaceholdergetByPlaceholder(text: string, options?: LocatorMatchOptions): Promise<ElementHandle | null>Finds an input or textarea by placeholder text.
getByAltTextgetByAltText(text: string, options?: LocatorMatchOptions): Promise<ElementHandle | null>Finds an image-like element by alt text.
getByTitlegetByTitle(text: string, options?: LocatorMatchOptions): Promise<ElementHandle | null>Finds an element by title attribute.
getByDataAttributegetByDataAttribute(name: string, value: string, options?: LocatorMatchOptions): Promise<ElementHandle | null>Finds an element by data-* attribute.
getByXPathgetByXPath(xpath: string): Promise<ElementHandle | null>Finds the first element matched by an XPath expression.
querySelectorAllquerySelectorAll(selector: string): Promise<ElementHandle[]>Gets all matching element references from a CSS selector.
querySelectorWithinquerySelectorWithin(parent: ElementHandle, selector: string): Promise<ElementHandle | null>Runs a scoped query inside an existing element reference.
querySelectorAllWithinquerySelectorAllWithin(parent: ElementHandle, selector: string): Promise<ElementHandle[]>Runs a scoped query that returns all matches inside an existing element reference.
getAttributegetAttribute(target: ElementHandle, name: string): Promise<string | null>Reads an attribute from an element reference.
disposeElementdisposeElement(target: ElementHandle): Promise<void>Disposes a stored element reference in the page bridge.
waitForElementwaitForElement(selector: string, options?: WaitForElementOptions): Promise<boolean>Waits for selector using observer or polling strategy.
getElementBoundsgetElementBounds(target: string | ElementHandle, timeoutMs?: number): Promise<ElementBounds>Resolves element bounds by selector or reference.
getElementCentergetElementCenter(target: string | ElementHandle, options?: ElementPointOptions): Promise<{ x: number; y: number }>Resolves clickable center point by selector or reference.
findEditableClickTargetfindEditableClickTarget(): Promise<ClickTarget>Finds best editable element target and click point.
clickEditableTargetclickEditableTarget(): Promise<ClickTarget>Clicks editable target and returns point metadata.
getActiveElementStategetActiveElementState(): Promise<{ tag: string; isEditable: boolean; value: string | null; text: string | null }>Returns active element editability/value snapshot.
MemberSignatureDescription
evaluateevaluate<T = unknown>(script: string, options?: EvaluateOptions): Promise<T>Evaluates JavaScript in page context with queued/non-blocking mode support.
MemberSignatureDescription
typetype(text: string, options?: TypeOptions): Promise<void>Types text into focused element with optional per-character delay.
clickclick(selector: string, options?: ClickSelectorOptions): Promise<void>Clicks selector-resolved point.
clickclick(target: ElementHandle, options?: ClickSelectorOptions): Promise<void>Clicks an existing element reference.
clickclick(x: number, y: number, options?: ClickOptions): Promise<void>Clicks explicit viewport coordinates.
clickAtclickAt(x: number, y: number): Promise<void>Direct coordinate click helper.
presspress(key: string, options?: PressOptions): Promise<void>Sends key press with modifier support.
resizeresize(width: number, height: number): Promise<void>Updates browser viewport size.
scrollscroll(dx: number, dy: number): Promise<void>Scrolls by delta values.
scrollToscrollTo(selector: string, options?: ScrollToOptions): Promise<void>Scrolls element into view by selector.
MemberSignatureDescription
screenshotscreenshot(options?: ScreenshotOptions): Promise<Blob | Uint8Array | string | { name: string; size: number }>General screenshot API with multiple output encodings.
captureViewportcaptureViewport(options?: ScreenshotOptions): Promise<Blob | Uint8Array | string>Captures full viewport.
captureElementcaptureElement(selector: string, options?: ScreenshotOptions): Promise<Blob | Uint8Array | string>Captures a selector-bounded region.
captureRegioncaptureRegion(x: number, y: number, width: number, height: number, options?: ScreenshotOptions): Promise<Blob | Uint8Array | string>Captures an explicit rectangle.
MemberSignatureDescription
getProcessIdgetProcessId(): numberReturns attached process ID (if provided) or spawned Chrome PID.
closeclose(): Promise<void>Idempotent shutdown: rejects pending CDP calls, closes socket, and kills owned process.
closeAllstatic closeAll(): voidCloses all tracked ChromeWebView instances.
[Symbol.dispose][Symbol.dispose](): voidSync dispose hook that initiates close.
[Symbol.asyncDispose][Symbol.asyncDispose](): Promise<void>Async dispose hook that awaits close completion.
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();

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 browser load event.
  • 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 an EventSource connection and where you want to wait for the first SSE message.
  • load and domcontentloaded are page lifecycle milestones, so they may never fire for top-level streaming responses such as text/event-stream.
  • frameNavigated and responseReceived are earlier signals than DOM readiness. They confirm navigation commit or HTTP response, not that the page is interactive.
  • eventSourceMessageReceived is for in-page EventSource requests. It is not a general signal for navigating the main frame directly to an SSE URL.
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();
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();