Skip to main content

What is act()?

await stagehand.act("click on add to cart")
act enables Stagehand to perform individual actions on a web page. Use it to build self-healing and deterministic automations that adapt to website changes.

Why use act()?

Using act()

Use act to perform single actions in your automation. Here’s how to click a button:
await page.goto("https://example-store.com");
await stagehand.act("click the add to cart button");
iFrame and Shadow DOM Support Stagehand automatically handles iFrame traversal and shadow DOM elements without requiring additional configuration.
With act, breaking complex actions into small, single-step actions works best. If you need to orchestrate multi-step flows, use multiple act commands or agent.
ActionExample instruction
Clickclick the button
Fillfill the field with <value>
Typetype <text> into the search box
Presspress <key> in the search field
Scrollscroll to <position>
Select from dropdownselect <value> from the dropdown

Return value of act()?

When you use act(), Stagehand will return a Promise<ActResult> with the following structure:
{
  success: true,
  message: 'Action [click] performed successfully on selector: xpath=/html[1]/body[1]/div[1]/span[1] → Action [click] performed successfully on selector: xpath=/html[1]/body[1]/div[2]/div[1]/section[1]/div[1]/div[1]/div[25]',
  actionDescription: 'Favorite Colour',
  actions: [
    {
      selector: 'xpath=/html[1]/body[1]/div[1]/span[1]',
      description: 'Favorite Colour',
      method: 'click',
      arguments: []
    },
    {
      selector: 'xpath=/html[1]/body[1]/div[2]/div[1]/section[1]/div[1]/div[1]/div[25]',
      description: 'Peach',
      method: 'click',
      arguments: []
    }
  ]
}
  • Do this
  • Don't do this
Break your task into single-step actions.
// Break it into single-step actions
await stagehand.act("open the filters panel");
await stagehand.act("choose 4-star rating");
await stagehand.act("click the apply button");

Advanced Configuration

You can pass additional options to configure the model, timeout, variables, and target page:
// Custom model configuration
await stagehand.act("choose 'Peach' from the favorite color dropdown", {
  model: {
    modelName: "google/gemini-2.5-flash",
    apiKey: process.env.GEMINI_API_KEY
  },
  timeout: 10000
});

Using with Custom Pages

You can use act() with pages from other browser automation libraries like Puppeteer, Playwright, or Patchright by passing the page option:
import { Stagehand } from "@browserbasehq/stagehand";
import puppeteer from "puppeteer-core";

const stagehand = new Stagehand({
  env: "BROWSERBASE",
});
await stagehand.init();

// Connect with Puppeteer
const browser = await puppeteer.connect({
  browserWSEndpoint: stagehand.connectURL(),
  defaultViewport: null,
});

const pages = await browser.pages();
const customPage = pages[0];

await customPage.goto("https://www.example.com/blog");

// Use act with the custom Puppeteer page
await stagehand.act("click the next page button", {
  page: customPage
});
This works with:
  • Puppeteer: Pass Puppeteer Page objects
  • Playwright: Pass Playwright Page objects
  • Patchright: Pass Patchright Page objects
  • Stagehand Page: Use stagehand.context.pages()[0] or context.activePage() (default)

Complete API Reference

See the full act() reference for detailed parameter documentation, return values, and advanced examples.

Best practices

Ensure reliable actions

Use observe() to discover candidate actions on the current page and plan reliably. It returns a list of suggested actions (with selector, description, method, and arguments). You can pass an observed action directly to act to execute it.
const [action] = await stagehand.observe("click the login button");

if (action) {
  await stagehand.act(action);
}

Analyze pages with observe()

Plan actions with observe() before executing with act.

Reduce model costs

Enable automatic action caching by specifying a cacheDir when initializing Stagehand. The first time an action runs, it’s cached. Subsequent runs reuse the cached action without LLM calls.
import { Stagehand } from "@browserbasehq/stagehand";

// Enable caching by specifying a cache directory
const stagehand = new Stagehand({
  env: "BROWSERBASE",
  cacheDir: "act-cache" // Actions are automatically cached here
});

await stagehand.init();
const page = stagehand.context.pages()[0];

// First run - makes LLM call and caches the action
await stagehand.act("click the login button");
Caching persists across script executions. The first time you run your script, actions are cached to your local filesystem. On subsequent runs, cached actions are reused automatically, significantly reducing costs and improving performance.

Complete caching guide

Learn advanced caching techniques and patterns for optimal performance.

Secure your automations

Variables are not shared with LLM providers. Use them for passwords, API keys, and other sensitive data.
Load sensitive data from environment variables using .env files. Never hardcode API keys, passwords, or other secrets directly in your code.
// Variables use %variableName% syntax in the instruction
await stagehand.act("type %username% into the email field", {
  variables: { username: "user@example.com" }
});

await stagehand.act("type %password% into the password field", {
  variables: { password: process.env.USER_PASSWORD }
});

await stagehand.act("click the login button");
When handling sensitive data, set verbose: 0 in your Stagehand configuration to prevent secrets from appearing in logs. See the configuration guide for more details.

User Data Best Practices

Complete guide to securing your browser automations with best practices and configurations.

Troubleshooting

Problem: act fails with “method not supported” errorSolutions:
  • Use clear and detailed instructions for what you want to accomplish
  • Review our evals to find the best models for your use case
  • Use observe() and verify the resulting action is within a list of expected actions
Solution 1: Validate with observe
const prompt = "click the submit button";
const expectedMethod = "click";

try {
  await stagehand.act(prompt);
} catch (error) {
  if (error.message.includes("method not supported")) {
    // Observe the same prompt to get the planned action
    const [action] = await stagehand.observe(prompt);

    if (action && action.method === expectedMethod) {
      await stagehand.act(action);
    } else {
      throw new Error(`Unsupported method: expected "${expectedMethod}", got "${action?.method}"`);
    }
  } else {
    throw error;
  }
}
Solution 2: Retry with exponential backoff
// Retry with exponential backoff for intermittent issues
const prompt = "click the submit button";
const maxRetries = 3;

for (let attempt = 0; attempt <= maxRetries; attempt++) {
  try {
    await stagehand.act(prompt, { timeout: 10000 + (attempt * 5000) });
    break; // Success, exit retry loop
  } catch (error) {
    if (error.message.includes("method not supported") && attempt < maxRetries) {
      // Exponential backoff: wait 2^attempt seconds
      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Retry ${attempt + 1}/${maxRetries} after ${delay}ms`);
      await new Promise(resolve => setTimeout(resolve, delay));
    } else {
      throw error;
    }
  }
}
Problem: act times out or fails to complete action (often due to element not found)Solutions:
// Handle timeout and element not found issues
try {
  await stagehand.act("click the submit button", { timeout: 30000 });
} catch (error) {
  // Check if page is fully loaded
  await page.waitForLoadState('domcontentloaded');

  // Use observe to check element state
  const [element] = await stagehand.observe("find the submit button");

  if (element) {
    console.log("Element found, trying more specific instruction");
    await stagehand.act("click the submit button at the bottom of the form");
  } else {
    console.log("Element not found, trying alternative selector");
    await stagehand.act("click the button with text 'Submit'");
  }
}
Problem: act performs action on wrong elementSolutions:
  • Be more specific in instructions: include visual cues, position, or context
  • Use observe() to preview which element will be selected
  • Add contextual information: “the search button in the header”
  • Use unique identifiers when available
// More precise element targeting
// Instead of:
await stagehand.act("click the button");

// Use specific context:
await stagehand.act("click the red 'Delete' button next to the user John Smith");

// Or preview with observe first:
const [action] = await stagehand.observe("click the submit button in the checkout form");
if (action.description.includes("checkout")) {
  await stagehand.act(action);
}

Next steps