Skip to main content
isoldex
Migration guide

Migrate from Stagehand
in under 10 minutes.

The API is intentionally similar. Most migrations are a find-and-replace away — and you immediately gain a 40× cost reduction and features Stagehand doesn't have.

API quick-reference

StagehandSentinel
new Stagehand({ env: 'LOCAL' })new Sentinel({ apiKey })
stagehand.init()sentinel.init()
stagehand.act({ action: '...' })sentinel.act('...')
stagehand.extract({ instruction, schema })sentinel.extract(instruction, schema)
stagehand.observe({ instruction })sentinel.observe(instruction)
stagehand.pagesentinel.page
stagehand.close()sentinel.close()
— (manual loop)sentinel.run(goal)
— (not available)Sentinel.parallel(tasks, options)
— (not available)sentinel.extend(page)

Step-by-step migration

Five steps, most under 30 seconds each.

01

Replace the package

Uninstall Stagehand, install Sentinel and the Playwright browser binary.

Before
npm install @browserbasehq/stagehand
After
npm install @isoldex/sentinel playwright
npx playwright install chromium
02

Update the import

Replace the Stagehand import with Sentinel. Pass your Gemini API key — free tier covers thousands of runs.

Before
import { Stagehand } from '@browserbasehq/stagehand';

const stagehand = new Stagehand({ env: 'LOCAL' });
await stagehand.init();
const { page } = stagehand;
After
import { Sentinel } from '@isoldex/sentinel';

const sentinel = new Sentinel({ apiKey: process.env.GEMINI_API_KEY });
await sentinel.init();
03

Simplify act() calls

Remove the object wrapper. Sentinel's act() takes a plain string — shorter and easier to read.

Before
await stagehand.act({ action: 'Click the login button' });
await stagehand.act({ action: 'Fill "user@example.com" into the email field' });
After
await sentinel.act('Click the login button');
await sentinel.act('Fill "user@example.com" into the email field');
04

Update extract()

Move the instruction to the first argument. The Zod schema stays the same — no changes needed there.

Before
import { z } from 'zod';

const result = await stagehand.extract({
  instruction: 'Get all product names and prices',
  schema: z.object({
    products: z.array(z.object({
      name: z.string(),
      price: z.number(),
    }))
  }),
});
After
import { Sentinel, z } from '@isoldex/sentinel';

const result = await sentinel.extract(
  'Get all product names and prices',
  z.object({
    products: z.array(z.object({
      name: z.string(),
      price: z.number(),
    }))
  })
);
observe() — Before
const elements = await stagehand.observe({
  instruction: 'Find all login-related elements',
});
observe() — After
const elements = await sentinel.observe('Find all login-related elements');
05

Replace the agent loop (optional)

If you wrote a manual loop over act() + extract() calls, replace it with sentinel.run(goal). Sentinel handles planning, retries, and reflection automatically.

Before (manual loop)
// Stagehand has no built-in agent loop — you write the loop manually:
await stagehand.act({ action: 'Search for laptop' });
await stagehand.act({ action: 'Click the first result' });
const data = await stagehand.extract({ instruction: '...', schema });
After (autonomous)
// Sentinel runs autonomously until the goal is achieved:
const result = await sentinel.run(
  'Go to Amazon, search for laptop, extract the top 5 results'
);
console.log(result.data);       // extracted products
console.log(result.selectors);  // stable CSS selectors for Playwright tests
console.log(result.totalSteps); // how many steps it took
Before
await stagehand.close();
After
await sentinel.close();

Full example

Amazon product search — before and after.

stagehand-example.ts
import { Stagehand } from '@browserbasehq/stagehand';
import { z } from 'zod';

const stagehand = new Stagehand({ env: 'LOCAL' });
await stagehand.init();
const { page } = stagehand;

await page.goto('https://amazon.de');
await stagehand.act({ action: 'Search for laptop' });

const data = await stagehand.extract({
  instruction: 'Get the top 3 products with name and price',
  schema: z.object({
    products: z.array(z.object({
      name: z.string(),
      price: z.string(),
    }))
  }),
});

console.log(data.products);
await stagehand.close();
sentinel-example.ts
import { Sentinel, z } from '@isoldex/sentinel';

const sentinel = new Sentinel({ apiKey: process.env.GEMINI_API_KEY });
await sentinel.init();

await sentinel.goto('https://amazon.de');

const result = await sentinel.run(
  'Search for laptop, extract the top 3 results with name and price'
);

console.log(result.data.products);
await sentinel.close();

What you gain for free

Everything below works out of the box — no extra config.

40× cheaper

Gemini Flash at $0.002/run vs. GPT-4o at $0.08/run. Same task, 40× less cost.

🔁

Self-healing locators

Successful selectors are cached and reused. LLM only called when an element breaks.

🤖

Built-in agent loop

sentinel.run(goal) plans, executes, verifies, and reflects — no manual loop required.

⚙️

Parallel execution

Sentinel.parallel() runs N tasks concurrently. Stagehand has no equivalent.

📡

OpenTelemetry

Every call emits traces and metrics. Drop into Datadog, Grafana, or Jaeger.

🔌

Any LLM

Gemini, OpenAI, Claude, Ollama — swap with one line. Stagehand is OpenAI-only.

🖥️

MCP Server

Use Sentinel directly inside Cursor, Windsurf, or Claude Desktop. No code needed.

🧪

Playwright Test fixture

import { test } from '@isoldex/sentinel/test' — drop-in ai fixture for existing suites.

Ready to migrate?

Install takes 30 seconds. The free Gemini tier covers thousands of runs.