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.
Use act to perform single actions in your automation. Here’s how to click a button:
await page.goto("https://example-store.com");await page.act("click the add to cart button");
await page.goto("https://example-store.com")await page.act("click the add to cart button")
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.
Suggested actions
Action
Example instruction
Click
click the button
Fill
fill the field with <value>
Type
type <text> into the search box
Press
press <key> in the search field
Scroll
scroll to <position>
Select from dropdown
select <value> from the dropdown
Do this
Don't do this
Break your task into single-step actions.
// Break it into single-step actionsawait page.act("open the filters panel");await page.act("choose 4-star rating");await page.act("click the apply button");
# Break it into single-step actionsawait page.act("open the filters panel")await page.act("choose 4-star rating")await page.act("click the apply button")
For advanced scenarios, you can configure additional options:
// Dynamic food search with advanced optionsconst foodItem = "organic quinoa";await page.act({ action: "Type %foodItem% in the search box and press enter", variables: { foodItem: foodItem }, modelName: "google/gemini-2.5-pro", modelClientOptions: { modelApiKey: process.env.GOOGLE_API_KEY, }, iframes: true, // Search within iframes if needed domSettleTimeoutMs: 45000, // Wait longer for dynamic content timeoutMs: 60000 // Extended timeout for slow-loading forms});
# Dynamic food search with advanced optionsfood_item = "organic quinoa"await page.act({ "action": "Type %foodItem% in the search box and press enter", "variables": { "foodItem": food_item }, "modelName": "google/gemini-2.5-pro", "modelClientOptions": { "modelApiKey": os.environ.get("GOOGLE_API_KEY") }, "iframes": True, # Search within iframes if needed "domSettleTimeoutMs": 45000, # Wait longer for dynamic content "timeoutMs": 60000 # Extended timeout for slow-loading forms})
Shadow DOM support is now available! Set experimental: true in your Stagehand configuration to enable it. See the configuration guide for more details.
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.
Variables will not be 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.
await page.act({ action: "enter %username% in the email field", variables: { username: "user@example.com" }});await page.act({ action: "enter %password% in the password field", variables: { password: process.env.USER_PASSWORD }});
# If using Python, set `use_api: true` in your Stagehand configurationawait page.act( "enter %username% in the email field", variables={ "username": "user@example.com" })await page.act( "enter %password% in the password field", variables={ "password": os.environ.get("USER_PASSWORD") })
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.
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 page.act(prompt);} catch (error) { if (error.message.includes("method not supported")) { // Observe the same prompt to get the planned action const [action] = await page.observe(prompt); if (action && action.method === expectedMethod) { await page.act(action); } else { throw new Error(`Unsupported method: expected "${expectedMethod}", got "${action?.method}"`); } } else { throw error; }}
prompt = "click the submit button"expected_method = "click"try: await page.act(prompt)except Exception as error: if "method not supported" in str(error): # Observe the same prompt to get the planned action results = await page.observe(prompt) if results and results[0].method == expected_method: await page.act(results[0]) else: method = results[0].method if results else "unknown" raise Exception(f'Unsupported method: expected "{expected_method}", got "{method}"') else: raise error
// Handle timeout and element not found issuestry { await page.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 page.observe("find the submit button"); if (element) { console.log("Element found, trying more specific instruction"); await page.act("click the submit button at the bottom of the form"); } else { console.log("Element not found, trying alternative selector"); await page.act("click the button with text 'Submit'"); }}
# Handle timeout and element not found issuestry: await page.act("click the submit button", {"timeout": 30000})except Exception as error: # Check if page is fully loaded await page.wait_for_load_state('domcontentloaded') # Use observe to check element state results = await page.observe("find the submit button") if results: print("Element found, trying more specific instruction") await page.act("click the submit button at the bottom of the form") else: print("Element not found, trying alternative selector") await page.act("click the button with text 'Submit'")
Incorrect element selected
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 page.act("click the button");// Use specific context:await page.act("click the red 'Delete' button next to the user John Smith");// Or preview with observe first:const [action] = await page.observe("click the submit button in the checkout form");if (action.description.includes("checkout")) { await page.act(action);}
# More precise element targeting# Instead of:await page.act("click the button")# Use specific context:await page.act("click the red 'Delete' button next to the user John Smith")# Or preview with observe first:results = await page.observe("click the submit button in the checkout form")if results and "checkout" in results[0].description: await page.act(results[0])