Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/l-xiaoshen/handstage/llms.txt

Use this file to discover all available pages before exploring further.

Page represents a single top-level browser tab. You receive a Page from context.newPage(), context.activePage(), or context.pages(). Each Page owns its own CDP session and manages all out-of-process iframe child sessions internally.

page.goto

Navigate the page to a URL and wait for a lifecycle state.
const response = await page.goto("https://example.com")
const response = await page.goto("https://example.com", {
  waitUntil: "networkidle",
  timeoutMs: 30000,
})
url
string
required
The URL to navigate to.
options.waitUntil
LoadState
default:"domcontentloaded"
Lifecycle event to wait for before resolving. One of "load", "domcontentloaded", or "networkidle".
options.timeoutMs
number
default:"15000"
Maximum navigation time in milliseconds.
Returns Promise<Response | null>

page.reload

Reload the current page.
await page.reload()
await page.reload({ waitUntil: "load", ignoreCache: true })
options.waitUntil
LoadState
Lifecycle event to wait for. One of "load", "domcontentloaded", or "networkidle".
options.timeoutMs
number
default:"15000"
Maximum reload time in milliseconds.
options.ignoreCache
boolean
default:"false"
When true, the browser bypasses its cache for the reload.
Returns Promise<Response | null>

page.goBack

Navigate to the previous entry in browser history. Returns null if there is no previous entry.
const response = await page.goBack()
const response = await page.goBack({ waitUntil: "load", timeoutMs: 10000 })
options.waitUntil
LoadState
Lifecycle event to wait for after navigating back.
options.timeoutMs
number
default:"15000"
Maximum time to wait in milliseconds.
Returns Promise<Response | null>

page.goForward

Navigate to the next entry in browser history. Returns null if there is no forward entry.
const response = await page.goForward()
options.waitUntil
LoadState
Lifecycle event to wait for after navigating forward.
options.timeoutMs
number
default:"15000"
Maximum time to wait in milliseconds.
Returns Promise<Response | null>

page.waitForLoadState

Wait until the page reaches the specified lifecycle state on the main frame.
await page.waitForLoadState("networkidle")
await page.waitForLoadState("load", 20000)
state
LoadState
required
One of "load", "domcontentloaded", or "networkidle".
timeoutMs
number
default:"15000"
Maximum time to wait in milliseconds.
Returns Promise<void>

LoadState type

type LoadState = "load" | "domcontentloaded" | "networkidle"
ValueFires when
"load"The load event fires on the window.
"domcontentloaded"The DOMContentLoaded event fires.
"networkidle"No network requests for at least 500 ms.

Page information

page.url

Return the current page URL. This is a synchronous, cached value updated from CDP navigation events.
const currentUrl = page.url()
Returns string

page.title

Return the current document title. Reads from the live document via Runtime.evaluate, falling back to navigation history if evaluation is unavailable.
const title = await page.title()
Returns Promise<string>

Capture

page.snapshot

Capture an accessibility tree snapshot of the page. The snapshot includes a formatted text tree suitable for LLM consumption, along with XPath and URL maps for element resolution.
const snapshot = await page.snapshot()
console.log(snapshot.formattedTree)

// Include iframes in the snapshot
const full = await page.snapshot({ includeIframes: true })
options.includeIframes
boolean
default:"false"
When true, iframe content is included in the accessibility tree.
Returns Promise<SnapshotResult>

SnapshotResult type

formattedTree
string
required
A human-readable accessibility tree as a formatted string.
xpathMap
Record<string, string>
required
Map from snapshot node references to their absolute XPath expressions.
urlMap
Record<string, string>
required
Map from snapshot node references to their associated URLs (for links and iframes).

page.screenshot

Capture a screenshot of the page and return it as a Buffer.
const png = await page.screenshot()

const jpeg = await page.screenshot({
  type: "jpeg",
  quality: 85,
  fullPage: true,
})

// Save to disk
await page.screenshot({ path: "./screenshot.png" })
options.type
"png" | "jpeg"
default:"\"png\""
Image format.
options.quality
number
JPEG quality from 0–100. Only applies when type is "jpeg".
options.fullPage
boolean
default:"false"
Capture the full scrollable page instead of the viewport. Cannot be combined with clip.
options.clip
ScreenshotClip
Restrict capture to a rectangle in CSS pixels: { x, y, width, height }. Cannot be combined with fullPage.
options.animations
"disabled" | "allow"
default:"\"allow\""
Set to "disabled" to fast-forward finite CSS animations and pause infinite ones before capture.
options.caret
"hide" | "initial"
default:"\"hide\""
Hide the text caret during capture ("hide") or leave it as-is ("initial").
options.mask
Locator[]
Array of locators whose matched elements are covered with a colored overlay during capture.
options.maskColor
string
default:"\"#FF00FF\""
CSS color for mask overlays.
options.omitBackground
boolean
default:"false"
Make the default page background transparent. PNG only.
options.path
string
File path to write the screenshot to after capture. The file extension determines the format when type is not provided.
options.scale
"css" | "device"
default:"\"device\""
Render scale. "css" uses one pixel per CSS pixel; "device" uses the device pixel ratio.
options.style
string
Additional CSS injected into every frame before capture and removed afterwards.
options.timeout
number
Maximum capture duration in milliseconds before a timeout error is thrown.
Returns Promise<Buffer>

Locators and frames

page.locator

Create a Locator scoped to the current main frame. Supports CSS selectors and XPath.
const btn = page.locator("button[type=submit]")
await btn.click()

const heading = page.locator("//h1")
const text = await heading.textContent()
selector
string
required
A CSS selector, XPath expression (detected when starting with / or (), or text= prefix for text matching. Use explicit css=, xpath=, or text= prefixes to override auto-detection.
Returns Locator See Locator — element interaction API reference for all locator methods.

page.frameLocator

Return a FrameLocator that scopes subsequent locator calls to the content of a matched iframe element. Mirrors Playwright’s API.
const frame = page.frameLocator("iframe#checkout")
const btn = frame.locator("button.pay")
await btn.click()
selector
string
required
CSS selector for the iframe element.
Returns FrameLocator

Scripts and headers

page.addInitScript

Register a script to run at document start for this page only. The script is replayed on each navigation and applied to any out-of-process iframe sessions adopted by this page.
await page.addInitScript(() => {
  window.__pageReady = true
})

await page.addInitScript((config: { env: string }) => {
  window.__config = config
}, { env: "staging" })
script
string | Function
required
A JavaScript expression string or a serializable function.
arg
any
JSON-serializable argument passed to the script function.
Returns Promise<void>

page.setExtraHTTPHeaders

Attach additional HTTP headers to every request sent by this page’s CDP sessions, including adopted out-of-process iframe sessions.
await page.setExtraHTTPHeaders({
  "X-Request-ID": "abc-123",
})
headers
Record<string, string>
required
Key–value pairs of header names and values.
Returns Promise<void> Throws HandstagesSetExtraHTTPHeadersError if any session fails to apply the headers.

Console events

page.on

Subscribe to page events. Currently "console" is the supported event type.
page.on("console", (message) => {
  console.log(`[${message.type()}]`, message.text())
})
event
"console"
required
The event name to listen for.
listener
ConsoleListener
required
Callback invoked with a ConsoleMessage object for each console event.
Returns Page (for chaining)

page.once

Subscribe to the next occurrence of an event, then automatically unsubscribe.
page.once("console", (message) => {
  console.log("First console message:", message.text())
})
Returns Page (for chaining)

page.off

Remove a previously registered event listener.
const handler = (message: ConsoleMessage) => { /* ... */ }
page.on("console", handler)
// later:
page.off("console", handler)
Returns Page (for chaining)

Low-level CDP access

page.sendCDP

Send a raw CDP command through the page’s main session. Use this when you need access to CDP domains not otherwise exposed by the SDK.
// Enable the Runtime domain
await page.sendCDP("Runtime.enable")

// Evaluate JavaScript
const result = await page.sendCDP<{ result: { value: number } }>(
  "Runtime.evaluate",
  { expression: "1 + 1", returnByValue: true }
)
method
string
required
The CDP method name, e.g., "Page.enable" or "Runtime.evaluate".
params
object
Optional parameters for the CDP command.
Returns Promise<unknown>

Utilities and evaluation

page.evaluate

Evaluate a JavaScript expression or function in the page’s main frame main world. If a function is provided, it is stringified and called with the optional argument. The return value must be JSON-serializable.
// Expression string
const title = await page.evaluate("document.title")

// Function with argument
const result = await page.evaluate(
  (data: { x: number }) => data.x * 2,
  { x: 21 },
)
// result === 42
pageFunctionOrExpression
string | ((arg: Arg) => R | Promise<R>)
required
A JavaScript expression string or a serializable function.
arg
Arg
JSON-serializable argument passed to the function. Ignored for string expressions.
Returns Promise<R> Throws HandstagesEvalError if the expression throws inside the page context.

page.waitForTimeout

Wait for a fixed number of milliseconds. Useful for debugging or adding deliberate pauses between actions.
await page.waitForTimeout(500)
ms
number
required
Number of milliseconds to wait.
Returns Promise<void>

page.waitForSelector

Wait for an element matching the selector to appear in (or disappear from) the DOM. Uses MutationObserver for efficiency and pierces shadow DOM by default. Supports iframe hop notation with >>.
// Wait for a visible element (default)
await page.waitForSelector("button.submit")

// Wait for element to detach
await page.waitForSelector(".loading-spinner", { state: "detached" })

// Custom timeout and no shadow DOM piercing
await page.waitForSelector("#result", { timeout: 5000, pierceShadow: false })
selector
string
required
CSS selector to wait for. Use >> to hop into an iframe (e.g., "iframe#checkout >> .submit-btn").
options.state
"attached" | "detached" | "visible" | "hidden"
default:"\"visible\""
Element state to wait for.
options.timeout
number
default:"30000"
Maximum time to wait in milliseconds.
options.pierceShadow
boolean
default:"true"
When true, search inside shadow DOM roots.
Returns Promise<boolean>true when the condition is met.

page.click

Click at absolute viewport coordinates (CSS pixels). Dispatches mouseMovedmousePressedmouseReleased at the given point. Does not scroll — ensure the target is within the viewport first.
// Left-click at (x=200, y=400)
await page.click(200, 400)

// Right-click with XPath resolution
const xpath = await page.click(200, 400, { button: "right", returnXpath: true })
x
number
required
Horizontal coordinate in CSS pixels from the left edge of the viewport.
y
number
required
Vertical coordinate in CSS pixels from the top edge of the viewport.
options.button
"left" | "right" | "middle"
default:"\"left\""
Which mouse button to use.
options.clickCount
number
default:"1"
Number of clicks to dispatch.
options.returnXpath
boolean
When true, resolves the deepest element at the click coordinates and returns its absolute XPath. Returns undefined when XPath resolution fails.
Returns Promise<string> — The resolved XPath when returnXpath is true, otherwise an empty string.

page.setViewportSize

Override the page viewport to an exact CSS size and device scale factor. Useful for ensuring screenshots match a specific resolution.
await page.setViewportSize(1280, 720)
await page.setViewportSize(375, 812, { deviceScaleFactor: 3 })
width
number
required
Viewport width in CSS pixels.
height
number
required
Viewport height in CSS pixels.
options.deviceScaleFactor
number
default:"1"
Device pixel ratio. Values below 0.01 are clamped to 0.01.
Returns Promise<void>

page.deepLocator

Create a Locator that supports cross-iframe traversal using >> hop notation or deep XPath with iframe steps.
// Hop into an iframe
const btn = page.deepLocator("iframe#checkout >> button.pay")

// XPath with iframe step
const cell = page.deepLocator("//iframe[2]//td[1]")
await cell.click()
selector
string
required
A CSS selector with optional >> hops or an XPath expression including iframe steps.
Returns Locator

page.enableCursorOverlay

Enable a visual cursor overlay that tracks mouse position on the page. Injects a custom SVG cursor element into the page and keeps it in sync with pointer events. Useful for recording or debugging automation scripts.
await page.enableCursorOverlay()
await page.click(400, 300) // cursor overlay moves to (400, 300)
Returns Promise<void>

Tab lifecycle

page.close

Close this browser tab. Uses Target.closeTarget over CDP and waits up to 2 seconds for the target to disappear before releasing resources.
await page.close()
Returns Promise<void>

Build docs developers (and LLMs) love