Skip to main content

Overview

The quality of your prompts directly impacts Stagehand’s reliability and performance. This guide covers proven patterns for writing effective instructions.

General Principles

Be Specific and Clear

// ❌ Vague
await stagehand.act("do something");

// ✅ Specific
await stagehand.act("click the blue 'Add to Cart' button");

Use Imperative Language

// ❌ Passive/Unclear
await stagehand.act("the login button should be clicked");

// ✅ Direct command
await stagehand.act("click the login button");

Include Visual Descriptors

// ❌ Ambiguous
await stagehand.act("click the button");

// ✅ Descriptive
await stagehand.act("click the red 'Submit' button at the bottom of the form");

Act() Prompts

Clicking Elements

// Good examples
await stagehand.act("click the 'Sign In' button");
await stagehand.act("click the menu icon in the top right");
await stagehand.act("click the third product card");
await stagehand.act("click the checkbox next to 'I agree to terms'");

Filling Forms

// ❌ Missing context
await stagehand.act("type '[email protected]'");

// ✅ Specifies target
await stagehand.act("type '[email protected]' in the email field");
await stagehand.act("type 'password123' in the password input");
await stagehand.act("type 'John Doe' in the full name field");

Selecting from Dropdowns

await stagehand.act("select 'United States' from the country dropdown");
await stagehand.act("select 'Medium' from the size selector");
await stagehand.act("choose 'Blue' from the color options");
await stagehand.act("scroll down to the footer");
await stagehand.act("scroll to the reviews section");
await stagehand.act("hover over the 'Products' menu item");

Extract() Prompts

Specify What to Extract

// ❌ Too broad
const result = await stagehand.extract("get data");

// ✅ Specific fields
const result = await stagehand.extract(
  "get the product title, price, and availability status"
);

Use Structured Schemas

import { z } from "zod";

const productSchema = z.object({
  title: z.string().describe("The product name"),
  price: z.number().describe("Price in USD"),
  inStock: z.boolean().describe("Whether the product is available"),
  rating: z.number().optional().describe("Star rating out of 5"),
});

const result = await stagehand.extract(
  "extract the product details",
  { schema: productSchema }
);

// result.extraction is fully typed
console.log(result.extraction.title);
console.log(result.extraction.price);

List Extractions

const searchResultsSchema = z.object({
  results: z.array(z.object({
    title: z.string(),
    url: z.string(),
    description: z.string(),
  })),
});

const results = await stagehand.extract(
  "extract all search results including title, URL, and description",
  { schema: searchResultsSchema }
);

Observe() Prompts

Observe returns a list of actions to perform:
// Get multiple related actions
const actions = await stagehand.observe(
  "return actions to fill the login form with username '[email protected]' and password 'test123'"
);

for (const action of actions) {
  await stagehand.act(action);
}

Good Observe Patterns

// Form filling
const formActions = await stagehand.observe(
  "return actions to complete the signup form with name 'John', email '[email protected]', and phone '555-1234'"
);

// Multi-step workflows
const checkoutActions = await stagehand.observe(
  "return actions to proceed through checkout: select shipping, enter payment details, and confirm order"
);

Agent Instructions

Clear Goals

const agent = stagehand.agent();

// ❌ Too vague
await agent.execute({
  instruction: "do some stuff on Amazon",
  maxSteps: 10,
});

// ✅ Clear objective
await agent.execute({
  instruction: "search for 'wireless mouse' on Amazon and add the first result to cart",
  maxSteps: 10,
});

Break Down Complex Tasks

// ❌ Too complex for one agent call
await agent.execute({
  instruction: "research competitors, analyze pricing, create spreadsheet, and send email",
  maxSteps: 50,
});

// ✅ Break into smaller tasks
await agent.execute({
  instruction: "navigate to competitor website and extract product prices",
  maxSteps: 15,
});
// Then handle analysis and email separately

Include Stop Conditions

await agent.execute({
  instruction: "search for 'laptop' and add first result to cart, then stop",
  maxSteps: 10,
});

await agent.execute({
  instruction: "scroll through products until you find one under $50, then click it",
  maxSteps: 20,
});

Using System Prompts

Stagehand-Level System Prompts

const stagehand = new Stagehand({
  env: "LOCAL",
  systemPrompt: `You are automating an e-commerce website.
  - Always verify prices before adding to cart
  - If an item is out of stock, skip it
  - Prefer items with 4+ star ratings`,
});

Agent-Level System Prompts

const agent = stagehand.agent({
  systemPrompt: `You are a research assistant.
  - Extract data accurately
  - When information is missing, note it as 'N/A'
  - Today's date is ${new Date().toLocaleDateString()}`,
});

await agent.execute({
  instruction: "gather company information from the about page",
  maxSteps: 5,
});

Common Mistakes to Avoid

Overly Complex Instructions

// ❌ Too many steps in one instruction
await stagehand.act(
  "click the menu, then click products, then select laptops category, then filter by price under $1000, then sort by rating"
);

// ✅ Break into individual actions
await stagehand.act("click the menu button");
await stagehand.act("click the 'Products' link");
await stagehand.act("select 'Laptops' from the category filter");
await stagehand.act("select 'Under $1000' from the price filter");
await stagehand.act("sort by rating");

Ambiguous References

// ❌ Which button?
await stagehand.act("click the button");

// ✅ Specific reference
await stagehand.act("click the 'Add to Cart' button");

Missing Context

// ❌ What form?
await stagehand.act("submit the form");

// ✅ Identifies the form
await stagehand.act("submit the login form");
await stagehand.act("click the submit button in the contact form");

Using Variables

Dynamically insert values into prompts:
const userEmail = "[email protected]";
const password = "secure123";

await stagehand.act(
  "type '{{email}}' in the email field",
  { variables: { email: userEmail } }
);

await stagehand.act(
  "type '{{password}}' in the password field",
  { variables: { password } }
);

Variables with Agent

const searchTerm = "wireless keyboard";
const maxPrice = 50;

const agent = stagehand.agent();
await agent.execute({
  instruction: "search for '{{product}}' and find options under ${{price}}",
  maxSteps: 15,
  variables: {
    product: searchTerm,
    price: maxPrice.toString(),
  },
});

Testing Your Prompts

Iterate and Refine

// Start simple
await stagehand.act("click login");

// If it fails, add more detail
await stagehand.act("click the login button");

// If still failing, be very specific
await stagehand.act("click the blue 'Log In' button in the top right corner");

Use Verbose Mode During Development

const stagehand = new Stagehand({
  env: "LOCAL",
  verbose: 2, // See detailed logs
});

await stagehand.act("click submit");
// Logs will show what Stagehand "sees" and how it interprets your instruction

Prompt Engineering for Reliability

Handle Dynamic Content

// ❌ Brittle: relies on exact text
await stagehand.act("click the button that says 'Add to Cart'");

// ✅ Flexible: works with variations
await stagehand.act("click the button to add the item to the cart");

Account for Loading States

// Wait for content before acting
const page = stagehand.context.pages()[0];
await page.waitForLoadState("domcontentloaded");

await stagehand.act("click the first product");

Use Conditional Logic

try {
  await stagehand.act("click the cookie consent banner's accept button", {
    timeout: 5000,
  });
} catch (error) {
  // No banner appeared, continue
}

await stagehand.act("search for products");

Example: Complete Workflow

import { Stagehand } from "@browserbasehq/stagehand";
import { z } from "zod";

const stagehand = new Stagehand({
  env: "LOCAL",
  cacheDir: "./cache",
});
await stagehand.init();

const page = stagehand.context.pages()[0];
await page.goto("https://example-store.com");

// Clear, specific instructions
await stagehand.act("type 'laptop' in the search bar");
await stagehand.act("click the search button");

// Structured extraction
const productSchema = z.object({
  products: z.array(z.object({
    name: z.string(),
    price: z.number(),
    rating: z.number(),
  })),
});

const results = await stagehand.extract(
  "extract the name, price, and rating for all products shown",
  { schema: productSchema }
);

// Act on extracted data
if (results.extraction.products.length > 0) {
  await stagehand.act("click the first product in the search results");
}

await stagehand.close();

Build docs developers (and LLMs) love