> ## Documentation Index
> Fetch the complete documentation index at: https://stagehand-codex-replicate-pr-2348.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompting Best Practices

> Write effective prompts for reliable Stagehand automation

Good prompts make Stagehand reliable. Bad prompts cause failures. Here's how to write prompts that work consistently.

## Act Method

Use `act()` for single actions on web pages. Each action should be focused and clear.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Single, specific actions
  await page.act("click the 'Add to Cart' button");
  await page.act("type 'user@example.com' into the email field");

  // Bad - Multiple actions combined
  await page.act("fill out the form and submit it");
  await page.act("login with credentials and navigate to dashboard");
  ```

  ```python Python theme={null}
  # Good - Single, specific actions
  await page.act("click the 'Add to Cart' button")
  await page.act("type 'user@example.com' into the email field")

  # Bad - Multiple actions combined
  await page.act("fill out the form and submit it")
  await page.act("login with credentials and navigate to dashboard")
  ```
</CodeGroup>

### Use Element Types, Not Colors

Describe elements by their type and function rather than visual attributes like color.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Element types and descriptive text
  await page.act("click the 'Sign In' button");
  await page.act("type into the email input field");

  // Bad - Color-based descriptions
  await page.act("click the blue button");
  await page.act("type into the white input");
  ```

  ```python Python theme={null}
  # Good - Element types and descriptive text
  await page.act("click the 'Sign In' button")
  await page.act("type into the email input field")

  # Bad - Color-based descriptions
  await page.act("click the blue button")
  await page.act("type into the white input")
  ```
</CodeGroup>

### Use Descriptive Language

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Clear element identification
  await page.act("click the 'Next' button at the bottom of the form");
  await page.act("type into the search bar at the top of the page");

  // Bad - Vague descriptions
  await page.act("click next");
  await page.act("type into search");
  ```

  ```python Python theme={null}
  # Good - Clear element identification
  await page.act("click the 'Next' button at the bottom of the form")
  await page.act("type into the search bar at the top of the page")

  # Bad - Vague descriptions
  await page.act("click next")
  await page.act("type into search")
  ```
</CodeGroup>

### Choose the Right Action Verbs

* **Click** for buttons, links, checkboxes
* **Type** for text inputs
* **Select** for dropdowns
* **Check/uncheck** for checkboxes
* **Upload** for file inputs

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good
  await page.act("click the submit button");
  await page.act("select 'Option 1' from dropdown");

  // Bad
  await page.act("click submit");
  await page.act("choose option 1");
  ```

  ```python Python theme={null}
  # Good
  await page.act("click the submit button")
  await page.act("select 'Option 1' from dropdown")

  # Bad
  await page.act("click submit")
  await page.act("choose option 1")
  ```
</CodeGroup>

### Protect Sensitive Data

Variables keep sensitive information out of prompts and logs.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Secure approach
  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
    }
  });

  // Bad - Insecure approach
  await page.act("type 'mySecretPassword123' into the password field");
  ```

  ```python Python theme={null}
  import os

  # Good - Secure approach
  await 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")
    }
  )

  # Bad - Insecure approach
  await page.act("type 'mySecretPassword123' into the password field")
  ```
</CodeGroup>

<Warning>
  Set `verbose: 0` in your Stagehand config to prevent secrets from appearing in logs.
</Warning>

## Extract Method

Use `extract()` to pull structured data from pages. Define clear schemas and provide context.

### Schema Best Practices

Use descriptive field names, correct types, and detailed descriptions. Field descriptions provide context that helps the agent understand exactly what to extract.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Descriptive names, correct types, and helpful descriptions
  const productData = await page.extract({
    instruction: "Extract product information",
    schema: z.object({
      productTitle: z.string().describe("The main product name displayed on the page"),
      priceInDollars: z.number().describe("Current selling price as a number, without currency symbol"),
      isInStock: z.boolean().describe("Whether the product is available for purchase")
    })
  });

  // Bad - Generic names, wrong types, no descriptions
  const data = await page.extract({
    instruction: "Get product details", 
    schema: z.object({
      name: z.string(), // Too generic, no context
      price: z.string(), // Should be number
      stock: z.string() // Should be boolean, no context
    })
  });
  ```

  ```python Python theme={null}
  from pydantic import BaseModel, Field

  # Good - Descriptive names, correct types, and helpful descriptions
  class ProductData(BaseModel):
      productTitle: str = Field(description="The main product name displayed on the page")
      priceInDollars: float = Field(description="Current selling price as a number, without currency symbol")
      isInStock: bool = Field(description="Whether the product is available for purchase")

  productData = await page.extract(
    "Extract product information",
    schema=ProductData
  )

  # Bad - Generic names, wrong types, no descriptions
  class Data(BaseModel):
      name: str      # Too generic, no context
      price: str     # Should be float, no context
      stock: str     # Should be bool, no context

  data = await page.extract(
    "Get product details",
    schema=Data
  )
  ```
</CodeGroup>

### Handle Arrays Correctly

Always wrap schemas in objects for reliable extraction.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Array wrapped in object
  const listings = await page.extract({
    instruction: "Extract all apartment listings",
    schema: z.object({
      apartments: z.array(z.object({
        address: z.string(),
        rent: z.number()
      }))
    })
  });

  // Bad - Bare array
  const listings = await page.extract({
    instruction: "Extract apartment listings",
    schema: z.array(z.string()) // Don't do this
  });
  ```

  ```python Python theme={null}
  from pydantic import BaseModel
  from typing import List

  # Good - Array wrapped in object
  class Apartment(BaseModel):
      address: str
      rent: float

  class Listings(BaseModel):
      apartments: List[Apartment]

  listings = await page.extract(
    "Extract all apartment listings",
    schema=Listings
  )

  # Bad - Bare array (not supported)
  # Don't do this - arrays must be wrapped in objects
  ```
</CodeGroup>

### Use Proper URL Types

Specify URL types to tell Stagehand to extract URLs. Without proper URL types, Stagehand won't extract URLs.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Tells Stagehand to extract URLs
  const links = await page.extract({
    instruction: "Extract navigation links",
    schema: z.object({
      links: z.array(z.object({
        text: z.string(),
        url: z.string().url() // Required for URL extraction
      }))
    })
  });
  ```

  ```python Python theme={null}
  from pydantic import BaseModel, HttpUrl
  from typing import List

  # Good - Tells Stagehand to extract URLs
  class Link(BaseModel):
      text: str
      url: HttpUrl  # Required for URL extraction

  class Links(BaseModel):
      links: List[Link]

  links = await page.extract(
    "Extract navigation links",
    schema=Links
  )
  ```
</CodeGroup>

## Observe Method

Use `observe()` to discover actionable elements before acting on them.

### Check Elements First

Verify elements exist before taking action to avoid errors.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Check for elements first
  const loginButtons = await page.observe("Find the login button");

  if (loginButtons.length > 0) {
    await page.act(loginButtons[0]);
  } else {
    console.log("No login button found");
  }
  ```

  ```python Python theme={null}
  # Check for elements first
  login_buttons = await page.observe("Find the login button")

  if len(login_buttons) > 0:
      await page.act(login_buttons[0])
  else:
      print("No login button found")
  ```
</CodeGroup>

### Be Specific About Element Types

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Specific element types
  const submitButtons = await page.observe("Find submit button in the form");
  const dropdowns = await page.observe("Find the state dropdown menu");

  // Bad - Too vague
  const elements = await page.observe("Find submit stuff");
  const things = await page.observe("Find state selection");
  ```

  ```python Python theme={null}
  # Good - Specific element types
  submit_buttons = await page.observe("Find submit button in the form")
  dropdowns = await page.observe("Find the state dropdown menu")

  # Bad - Too vague
  elements = await page.observe("Find submit")
  things = await page.observe("Find state selection")
  ```
</CodeGroup>

## Agent Method

Use `agent()` for complex, multi-step workflows. Provide detailed instructions and set appropriate limits.

### Navigate First

Don't include navigation in agent tasks. Handle it separately.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Navigate first
  await page.goto('https://amazon.com');
  await agent.execute('Search for wireless headphones under $100 and add the best rated one to cart');

  // Bad - Navigation in task
  await agent.execute('Go to Amazon, search for headphones, and add one to cart');
  ```

  ```python Python theme={null}
  # Good - Navigate first
  await page.goto('https://amazon.com')
  await agent.execute('Search for wireless headphones under $100 and add the best rated one to cart')

  # Bad - Navigation in task
  await agent.execute('Go to Amazon, search for headphones, and add one to cart')
  ```
</CodeGroup>

### Be Highly Specific

Detailed instructions lead to better results.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Detailed instructions
  await agent.execute({
    instruction: "Find Italian restaurants in Brooklyn that are open after 10pm, have outdoor seating, and are rated 4+ stars. Save the top 3 results.",
    maxSteps: 25
  });

  // Bad - Vague instructions
  await agent.execute("Find some good restaurants");
  ```

  ```python Python theme={null}
  # Good - Detailed instructions
  await agent.execute(
    instruction="Find Italian restaurants in Brooklyn that are open after 10pm, have outdoor seating, and are rated 4+ stars. Save the top 3 results.",
    max_steps=25
  )

  # Bad - Vague instructions
  await agent.execute("Find some good restaurants")
  ```
</CodeGroup>

### Set Appropriate Step Limits

Match step limits to task complexity.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Simple task - fewer steps
  await agent.execute({
    instruction: "Subscribe to the newsletter with email 'user@example.com'",
    maxSteps: 10
  });

  // Complex task - more steps  
  await agent.execute({
    instruction: "Research and compare 5 project management tools with pricing and features",
    maxSteps: 50
  });
  ```

  ```python Python theme={null}
  # Simple task - fewer steps
  await agent.execute(
    instruction="Subscribe to the newsletter with email 'user@example.com'",
    max_steps=10
  )

  # Complex task - more steps
  await agent.execute(
    instruction="Research and compare 5 project management tools with pricing and features",
    max_steps=50
  )
  ```
</CodeGroup>

### Include Success Criteria

Tell the agent how to know when it's done.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Good - Clear success criteria
  await agent.execute({
    instruction: "Add 3 smartphone cases to cart and confirm the cart shows exactly 3 items with total price",
    maxSteps: 20
  });

  // Bad - No validation
  await agent.execute("Add some items to cart");
  ```

  ```python Python theme={null}
  # Good - Clear success criteria
  await agent.execute(
    instruction="Add 3 smartphone cases to cart and confirm the cart shows exactly 3 items with total price",
    max_steps=20
  )

  # Bad - No validation
  await agent.execute("Add some items to cart")
  ```
</CodeGroup>

## Common Mistakes to Avoid

* **Combining multiple actions** - Keep each `act()` call to one action
* **Using vague descriptions** - Be specific about which elements to interact with
* **Exposing sensitive data** - Always use variables for credentials
* **Skipping validation** - Check results before proceeding

## Testing Your Prompts

1. **Start simple** - Test basic functionality first
2. **Add complexity gradually** - Build up to complex workflows
3. **Monitor results** - Use logging to understand what's happening
4. **Iterate based on failures** - Refine prompts when they don't work
   Remember: Good prompting is iterative. When in doubt, be more specific rather than less.
