> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://platform.bctrl.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://platform.bctrl.ai/_mcp/server.

# Stagehand on BCTRL

> Compose act, observe, and extract into a deterministic flow - each step hosted, each step recorded.

Where a [full agent](/cookbook/hosted-agent) decides its own steps, Stagehand actions let *you* own the control flow and spend AI only on the fuzzy parts: one natural-language action, one observation, one extraction at a time. Each runs as a hosted [invocation](/sdk/invocations) - sequence them like ordinary async calls.

```ts
import { Bctrl } from "@bctrl/sdk";
import { z } from "zod";

const bctrl = new Bctrl({ apiKey: process.env.BCTRL_API_KEY! });

const runtime = await bctrl.runtimes.create({ type: "browser", name: "stagehand-recipe" });
await bctrl.runtimes.start(runtime.id);

await bctrl.runtimes.targets.create(runtime.id, {
  uri: "https://github.com/trending",
  activate: true,
});

// One natural-language action...
await bctrl.runtimes.invocations.createAndWait(runtime.id, {
  action: "act",
  instruction: "Switch the trending language filter to Python.",
});

// ...one structured read.
const result = await bctrl.runtimes.invocations.createAndWait(runtime.id, {
  action: "extract",
  instruction: "Extract the top 3 trending repositories.",
  schema: z.object({
    repos: z.array(
      z.object({
        name: z.string(),
        description: z.string(),
        starsToday: z.number(),
      })
    ),
  }),
});

console.log(result.output);

await bctrl.runtimes.stop(runtime.id);
```

Use `action: "observe"` between steps when the next move depends on what the page offers ("What filters are available?"). The `stagehand.act` / `.observe` / `.extract` / `.agent` helpers on `bctrl.runtimes.invocations` expose the same actions with richer options and return immediately - reach for them when you want to dispatch without blocking.

## When the flow gets long

If you're chaining more than a handful of steps with retries and branches, flip it around: hand the whole task to a multi-step agent and keep your code out of the loop.

```ts
await bctrl.runtimes.invocations.createAndWait(
  runtime.id,
  {
    action: "stagehandAgent",
    instruction: "Download every invoice from the last quarter.",
    maxSteps: 30,
  },
  { timeoutMs: 600_000 }
);
```

## Next

* [Hosted agents](/sdk/hosted-agents) - Stagehand and browser-use in depth
* [Extract Structured Data](/cookbook/extract-structured-data) - the extraction pattern on its own
* [Run a Hosted Agent](/cookbook/hosted-agent) - the fully autonomous version