Skip to main content

Overview

The Locator class provides precise element interaction capabilities. It resolves CSS or XPath selectors within a frame and performs low-level actions using Chrome DevTools Protocol (CDP). Create a locator through the page object:
const stagehand = new Stagehand({ env: "LOCAL" });
await stagehand.init();
const page = stagehand.context.pages()[0];

// Create a locator
const button = page.locator("button.submit");
await button.click();

Key Features

  • Lazy resolution - Selectors are resolved fresh on each action
  • Isolated execution - Runs in an isolated world, separate from page scripts
  • CDP-based - Uses Chrome DevTools Protocol for reliable interactions
  • Automatic cleanup - Releases remote objects automatically
  • Iframe support - Works seamlessly with iframes and shadow DOM

Interaction Methods

click()

Click the element at its visual center.
await locator.click(options?: ClickOptions): Promise<void>
button
"left" | "right" | "middle"
Mouse button to use for the click.Default: "left"
clickCount
number
Number of consecutive clicks (for double-click, triple-click).Default: 1
The method:
  1. Scrolls element into view
  2. Gets element geometry
  3. Moves mouse to center
  4. Dispatches mousePressed and mouseReleased events

fill()

Fill an input, textarea, or contenteditable element.
await locator.fill(value: string): Promise<void>
value
string
required
The text value to fill into the element.
The method intelligently handles different input types:
  • Uses native value setter for special inputs (date, number, etc.)
  • Types text character-by-character for regular inputs
  • Clears existing content before filling

type()

Type text into the element with optional delay between keystrokes.
await locator.type(text: string, options?: TypeOptions): Promise<void>
text
string
required
The text to type.
delay
number
Delay in milliseconds between each keystroke.If not specified, uses Input.insertText for efficiency.

hover()

Move the mouse cursor to the element’s center without clicking.
await locator.hover(): Promise<void>
Scrolls the element into view and dispatches a mouse move event.

selectOption()

Select one or more options in a <select> element.
await locator.selectOption(values: string | string[]): Promise<string[]>
values
string | string[]
required
Option value(s) to select. For multi-select elements, pass an array.
Returns: Promise<string[]> - Array of values that were actually selected.

setInputFiles()

Set files on an <input type="file"> element.
await locator.setInputFiles(files: FileInput): Promise<void>
files
string | string[] | FilePayload | FilePayload[]
required
File paths or file payloads to upload.File Path: Absolute or relative path to a fileFile Payload: Object with { name, mimeType, buffer }
FilePayload Interface:
interface FilePayload {
  name: string;
  mimeType: string;
  buffer: ArrayBuffer | Uint8Array | Buffer | string;
}
Pass an empty array to clear the file selection.

State Methods

isVisible()

Check if the element is visible.
await locator.isVisible(): Promise<boolean>
Returns: Promise<boolean> - true if element is attached and visible.

isChecked()

Check if a checkbox or radio button is checked.
await locator.isChecked(): Promise<boolean>
Returns: Promise<boolean> - true if checked. Also considers aria-checked for ARIA widgets.

inputValue()

Get the current value of an input element.
await locator.inputValue(): Promise<string>
Returns: Promise<string> - The element’s input value. Works with: <input>, <textarea>, <select>, contenteditable elements.

textContent()

Get the element’s text content (raw).
await locator.textContent(): Promise<string>
Returns: Promise<string> - The element’s textContent property.

innerText()

Get the element’s visible text (layout-aware).
await locator.innerText(): Promise<string>
Returns: Promise<string> - The element’s innerText property.

innerHtml()

Get the element’s HTML content.
await locator.innerHtml(): Promise<string>
Returns: Promise<string> - The element’s innerHtml.

Selection Methods

count()

Get the number of elements matching the selector.
await locator.count(): Promise<number>
Returns: Promise<number> - Count of matching elements.

nth()

Get a locator for the element at a specific index.
locator.nth(index: number): Locator
index
number
required
Zero-based index of the element to select.
Returns: Locator - New locator targeting the nth element.
// Get the third button
const thirdButton = page.locator("button").nth(2);
await thirdButton.click();

first()

Get a locator for the first matching element.
locator.first(): Locator
Returns: Locator - Returns the same locator (querySelector already returns first match).

Utility Methods

highlight()

Visually highlight the element with an overlay.
await locator.highlight(options?: HighlightOptions): Promise<void>
durationMs
number
How long to display the highlight in milliseconds.Default: 800
borderColor
{ r, g, b, a? }
Border color RGBA values (0-255).Default: { r: 255, g: 0, b: 0, a: 0.9 } (red)
contentColor
{ r, g, b, a? }
Content fill color RGBA values (0-255).Default: { r: 255, g: 200, b: 0, a: 0.2 } (yellow)
Useful for debugging and visual verification.

scrollTo()

Scroll the element to a specific position.
await locator.scrollTo(percent: number | string): Promise<void>
percent
number | string
required
Scroll position as percentage (0-100).
For <html> or <body> elements, scrolls the window. Otherwise, scrolls the element itself.

centroid()

Get the center coordinates of the element.
await locator.centroid(): Promise<{ x: number; y: number }>
Returns: Promise<{ x, y }> - Center point in CSS pixels.

backendNodeId()

Get the DOM backend node ID for the element.
await locator.backendNodeId(): Promise<BackendNodeId>
Returns: Promise<BackendNodeId> - Unique identifier for the DOM node. Useful for identity comparisons without maintaining element handles.

sendClickEvent()

Dispatch a DOM click event directly on the element.
await locator.sendClickEvent(options?: EventOptions): Promise<void>
bubbles
boolean
Whether the event bubbles.Default: true
cancelable
boolean
Whether the event is cancelable.Default: true
composed
boolean
Whether the event crosses shadow DOM boundaries.Default: true
detail
number
Click count detail.Default: 1
This dispatches an event directly without synthesizing real pointer input. Useful for elements that rely on click handlers without needing hit-testing.

Code Examples

  • Basic Interaction
  • Forms
  • File Upload
  • Element Selection
  • State Checks
  • Advanced Actions
import { Stagehand } from "@browserbasehq/stagehand";

// Initialize with Browserbase (API key and project ID from environment variables)
// Set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID in your environment
const stagehand = new Stagehand({ env: "BROWSERBASE" });
await stagehand.init();
const page = stagehand.context.pages()[0];

await page.goto("https://example.com");

// Click a button
const submitButton = page.locator("button[type=submit]");
await submitButton.click();

// Fill an input
const emailInput = page.locator("input[name=email]");
await emailInput.fill("user@example.com");

// Type with delay
const searchBox = page.locator("input[type=search]");
await searchBox.type("stagehand", { delay: 100 });

await stagehand.close();

Selector Support

Locators support both CSS and XPath selectors:

CSS Selectors

page.locator("button");                    // Tag
page.locator(".submit-btn");              // Class
page.locator("#login-form");              // ID
page.locator("button.primary");           // Tag + class
page.locator("input[type=email]");        // Attribute
page.locator("div > p");                  // Child
page.locator("h1 + p");                   // Adjacent sibling
page.locator("div.container button");     // Descendant

XPath Selectors

page.locator("//button");                               // Tag
page.locator("//button[@class='submit']");             // Attribute
page.locator("//div[@id='content']//p");               // Descendant
page.locator("//button[contains(text(), 'Submit')]");  // Text content
page.locator("(//button)[1]");                         // First button
page.locator("//input[@type='text'][1]");              // First text input

Best Practices

  1. Use specific selectors - Prefer IDs or unique attributes over generic selectors
  2. Chain with nth() - Use locator().nth() instead of putting index in selector
  3. Check state before action - Use isVisible(), isChecked() for conditional logic
  4. Let locators auto-resolve - Don’t store element handles, use locators which re-resolve
  5. Use fill() for inputs - Prefer fill() over click() + type() for better reliability
  6. Handle file uploads properly - Use absolute paths or buffer payloads for setInputFiles()
  7. Highlight for debugging - Use highlight() during development to verify targeting

Common Patterns

Conditional Interaction

const errorMessage = page.locator(".error-message");
if (await errorMessage.isVisible()) {
  const text = await errorMessage.textContent();
  console.log("Error:", text);
}

Wait and Interact

// Locators automatically wait during actions
const dynamicButton = page.locator("button.dynamic");
await dynamicButton.click(); // Waits for element to exist

Loop Through Elements

const items = page.locator("li.item");
const count = await items.count();

for (let i = 0; i < count; i++) {
  const item = items.nth(i);
  const text = await item.innerText();
  console.log(`Item ${i}:`, text);
}

Error Handling

Locator methods may throw the following errors:
  • Element not found - Selector doesn’t match any elements
  • Element not visible - Element exists but is not visible (for actions requiring visibility)
  • Invalid selector - Malformed CSS or XPath selector
  • Timeout errors - Operation exceeded timeout limits
  • CDP errors - Chrome DevTools Protocol communication errors
Handle errors appropriately:
try {
  await page.locator("button.submit").click();
} catch (error) {
  console.error("Click failed:", error.message);
}

Type Definitions

interface Locator {
  // Actions
  click(options?: { button?: MouseButton; clickCount?: number }): Promise<void>;
  fill(value: string): Promise<void>;
  type(text: string, options?: { delay?: number }): Promise<void>;
  hover(): Promise<void>;
  selectOption(values: string | string[]): Promise<string[]>;
  setInputFiles(files: FileInput): Promise<void>;

  // State
  isVisible(): Promise<boolean>;
  isChecked(): Promise<boolean>;
  inputValue(): Promise<string>;
  textContent(): Promise<string>;
  innerText(): Promise<string>;
  innerHtml(): Promise<string>;

  // Selection
  count(): Promise<number>;
  nth(index: number): Locator;
  first(): Locator;

  // Utilities
  highlight(options?: HighlightOptions): Promise<void>;
  scrollTo(percent: number | string): Promise<void>;
  centroid(): Promise<{ x: number; y: number }>;
  backendNodeId(): Promise<BackendNodeId>;
  sendClickEvent(options?: EventOptions): Promise<void>;
}