> ## Documentation Index
> Fetch the complete documentation index at: https://stagehand.readme-i18n.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Best Practices

> Prompting Stagehand places an emphasis on being atomic and specific. Here are some guidelines to help you use Stagehand effectively.

### Use Cursor rules for better AI suggestions

Most of the Stagehand team uses [Cursor](https://www.cursor.com/) to write code. Cursor has a feature called [rules](https://docs.cursor.com/context/rules-for-ai) that allows you to customize the AI's behavior. You can use these rules to make the AI more accurate when suggesting actions.

For Stagehand's Cursor rules, check out [this file](https://github.com/browserbase/stagehand-scaffold/blob/main/.cursorrules).

If you're using Windsurf, you can use the same rules by adding them to your `.windsurfrules` file.

### Avoid sending sensitive information to LLMs

You can use `variables` in an `act` call to avoid sending sensitive information to LLMs.

<CodeGroup>
  ```typescript TypeScript theme={null}
  await page.act({
  	action: "Type %email% into the email field",
  	variables: {
  		email: "john.doe@example.com",
  	},
  });
  ```

  ```python Python theme={null}
  await page.act({
  	"Type %email% into the email field",
  	variables={
  		"email": "john.doe@example.com",
  	}
  })
  ```
</CodeGroup>

### Preview actions before running them

You can use `observe()` to get an action to run without running it.
If you're satisfied with the action, you can run it with `act()` without any LLM inference.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const [topAction] = await page.observe("Click the quickstart link");

  /** The action will map 1:1 with a Playwright action:
  {
  	description: "The quickstart link",
  	method: "click",
  	selector: "/html/body/div[1]/div[1]/a",
  	arguments: [],
  }
  **/

  // NO LLM INFERENCE on observe results
  await page.act(topAction)
  ```

  ```python Python theme={null}
  actions = await page.observe("Click the quickstart link")
  top_action = actions[0]

  # The action will map 1:1 with a Playwright action:
  # {
  #		"description": "The quickstart link",
  #		"method": "click",
  #		"selector": "/html/body/div[1]/div[1]/a",
  #		"arguments": [],
  # }

  # NO LLM INFERENCE on observe results
  await page.act(top_action)
  ```
</CodeGroup>

You can also use `observe()` with sensitive information, like below.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const [topAction] = await page.observe("Type %email% into the email field");

  /** The observe result will be an object with the following shape:
  {
  	description: "The email input field",
  	method: "type",
  	selector: "/html/body/div[1]/div[1]/input",
  	arguments: ["%email%"],
  }
  */

  await page.act({
  	...topAction,
  	// This prevents LLMs from seeing sensitive information
  	// No LLM inference is taken on observe results
  	arguments: [sensitiveEmail],
  })
  ```

  ```python Python theme={null}
  actions = await page.observe("Type %email% into the email field")
  top_action = actions[0]

  # The observe result will be a dictionary with the following shape:
  # {
  #		"description": "The email input field",
  #		"method": "type",
  #		"selector": "/html/body/div[1]/div[1]/input",
  #		"arguments": ["%email%"],
  # }

  await page.act({
  	**top_action,
  	# This prevents LLMs from seeing sensitive information
  	# No LLM inference is taken on observe results
  	"arguments": [sensitive_email],
  })
  ```
</CodeGroup>

**Use `observe()` to get actionable suggestions from the current page**

<CodeGroup>
  ```typescript TypeScript theme={null}
  const actions = await page.observe();
  console.log("Possible actions:", actions);

  // You can also use `observe()` with a custom prompt
  const buttons = await page.observe({
  	instruction: "find all the buttons on the page",
  });
  ```

  ```python Python theme={null}
  actions = await page.observe()
  print("Possible actions:", actions)

  # You can also use `observe()` with a custom prompt
  buttons = await page.observe("find all the buttons on the page")
  ```
</CodeGroup>

### Avoid broad or ambiguous instructions

Avoid instructions that aren't specific to the current page or try to do multiple things at once.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Too vague
  await page.act({ action: "find something interesting on the page" });

  // Avoid combining actions
  await page.act({ action: "fill out the form and submit it" });
  ```

  ```python Python theme={null}
  # Too vague
  await page.act("find something interesting on the page")

  # Avoid combining actions
  await page.act("fill out the form and submit it")
  ```
</CodeGroup>

### Use `observe()` to get entire form values

<CodeGroup>
  ```typescript TypeScript theme={null}
  const formValues = await page.observe("get the text inputs on the page");
  ```

  ```python Python theme={null}
  form_values = await page.observe("get the text inputs on the page")
  ```
</CodeGroup>

This will return an array of objects with the following shape:

<CodeGroup>
  ```typescript TypeScript theme={null}
  {
  	description: "The text input field",
  	method: "type",
  	selector: "/html/body/div[1]/div[1]/input",
  	arguments: ["some text"],
  }
  ```

  ```python Python theme={null}
  {
  	"description": "The text input field",
  	"method": "type",
  	"selector": "/html/body/div[1]/div[1]/input",
  	"arguments": ["some text"],
  }
  ```
</CodeGroup>

You can then use these actions directly in your code.

<CodeGroup>
  ```typescript TypeScript theme={null}
  for (const formValue of formValues) {
  	await page.act({
  		...formValue,
  		arguments: [yourValueHere],
  	});
  }
  ```

  ```python Python theme={null}
  for form_value in form_values:
  	await page.act({
  		**form_value,
  		"arguments": [your_value_here],
  	})
  ```
</CodeGroup>

For a full example, check out the example in the Stagehand repo [here](https://github.com/browserbase/stagehand/blob/main/examples/form_filling_sensible.ts).
