🐍 Looking for Stagehand in Python?Switch to v2 →
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"
Number of consecutive clicks (for double-click, triple-click).Default: 1
The method:
- Scrolls element into view
- Gets element geometry
- Moves mouse to center
- Dispatches mousePressed and mouseReleased events
fill()
Fill an input, textarea, or contenteditable element.
await locator.fill(value: string): Promise<void>
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>
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.
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.
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
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.
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>
How long to display the highlight in milliseconds.Default: 800
Border color RGBA values (0-255).Default: { r: 255, g: 0, b: 0, a: 0.9 } (red)
Content fill color RGBA values (0-255).Default: { r: 255, g: 200, b: 0, a: 0.2 } (yellow)
Useful for debugging and visual verification.
Scroll the element to a specific position.
await locator.scrollTo(percent: number | string): Promise<void>
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>
Whether the event bubbles.Default: true
Whether the event is cancelable.Default: true
Whether the event crosses shadow DOM boundaries.Default: true
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("[email protected]");
// Type with delay
const searchBox = page.locator("input[type=search]");
await searchBox.type("stagehand", { delay: 100 });
await stagehand.close();
// Fill multiple form fields
const form = page.locator("form#login");
await page.locator("#username").fill("myuser");
await page.locator("#password").fill("mypass");
// Select from dropdown
await page.locator("select#country").selectOption("US");
// Multi-select
await page.locator("select#skills").selectOption(["js", "ts", "react"]);
// Check checkbox
const termsCheckbox = page.locator("input#terms");
const isChecked = await termsCheckbox.isChecked();
if (!isChecked) {
await termsCheckbox.click();
}
// Submit
await page.locator("button[type=submit]").click();
// Upload from file path
const fileInput = page.locator("input[type=file]");
await fileInput.setInputFiles("/path/to/document.pdf");
// Upload multiple files
await fileInput.setInputFiles([
"/path/to/image1.jpg",
"/path/to/image2.jpg"
]);
// Upload from buffer
await fileInput.setInputFiles({
name: "data.json",
mimeType: "application/json",
buffer: JSON.stringify({ key: "value" })
});
// Clear file selection
await fileInput.setInputFiles([]);
// Count elements
const buttons = page.locator("button");
const count = await buttons.count();
console.log(`Found ${count} buttons`);
// Click the first button
await buttons.first().click();
// Click the third button
await buttons.nth(2).click();
// Iterate with nth
for (let i = 0; i < count; i++) {
const button = buttons.nth(i);
const text = await button.innerText();
console.log(`Button ${i}: ${text}`);
}
// Check visibility
const modal = page.locator(".modal");
if (await modal.isVisible()) {
console.log("Modal is visible");
}
// Check checkbox state
const checkbox = page.locator("input#subscribe");
const checked = await checkbox.isChecked();
console.log("Subscribed:", checked);
// Get input value
const email = page.locator("input#email");
const value = await email.inputValue();
console.log("Email:", value);
// Get text content
const heading = page.locator("h1");
const text = await heading.textContent();
console.log("Heading:", text);
// Hover to reveal menu
const menuButton = page.locator("button.menu");
await menuButton.hover();
// Wait for submenu
await page.waitForLoadState("networkidle");
// Click submenu item
await page.locator("a.submenu-item").click();
// Highlight for debugging
await page.locator("div.error").highlight({
durationMs: 2000,
borderColor: { r: 255, g: 0, b: 0 },
contentColor: { r: 255, g: 0, b: 0, a: 0.1 }
});
// Scroll element into position
const section = page.locator("#section-3");
await section.scrollTo(50); // Scroll to 50%
// Get element position
const { x, y } = await section.centroid();
console.log(`Element center: ${x}, ${y}`);
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
- Use specific selectors - Prefer IDs or unique attributes over generic selectors
- Chain with nth() - Use
locator().nth() instead of putting index in selector
- Check state before action - Use
isVisible(), isChecked() for conditional logic
- Let locators auto-resolve - Don’t store element handles, use locators which re-resolve
- Use fill() for inputs - Prefer
fill() over click() + type() for better reliability
- Handle file uploads properly - Use absolute paths or buffer payloads for
setInputFiles()
- 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>;
}