Skip to main content

Overview

Optimizing Stagehand’s performance involves balancing speed, reliability, and cost. This guide covers proven strategies to reduce latency.

Use Caching for Speed

Caching is the single most effective performance optimization.

Enable Cache

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

await stagehand.init();
Performance impact:
  • Cached operations: 50-100ms (selector replay)
  • Uncached operations: 1-5 seconds (LLM inference)
  • Speed improvement: 10-50x

Cache Hit Verification

const result = await stagehand.extract("get product title");

if (result.metadata?.cacheHit) {
  console.log("Cache hit! Instant response.");
  console.log("Cache timestamp:", result.metadata.cacheTimestamp);
}

Optimize DOM Processing

Set DOM Settle Timeout

Reduce wait time for DOM stabilization:
const stagehand = new Stagehand({
  env: "LOCAL",
  domSettleTimeout: 500, // ms to wait for DOM changes
});
Lower values speed up execution but may miss dynamic content. Default is typically sufficient.

Use Faster Models

Smaller models have lower latency:
// Fast: ~500ms inference time
const stagehand = new Stagehand({
  model: "openai/gpt-4.1-mini",
});

// Slower but more accurate: ~1-2s inference time
const stagehand = new Stagehand({
  model: "anthropic/claude-sonnet-4",
});

Optimize Timeouts

Set Appropriate Timeouts

// Default timeout (varies by operation)
await stagehand.act("click submit");

// Custom timeout for slow-loading pages
await stagehand.act("click submit", {
  timeout: 30_000 // 30 seconds
});

// Fail fast for quick operations
await stagehand.act("click button", {
  timeout: 5_000 // 5 seconds
});

Agent Timeouts

const agent = stagehand.agent();

await agent.execute({
  instruction: "search for product",
  maxSteps: 5, // Limit exploration
  // Each step can have its own timeout
});
Set maxSteps to the minimum required for your task to avoid unnecessary LLM calls.

Use Browserbase for Scale

Browserbase provides infrastructure optimizations:
const stagehand = new Stagehand({
  env: "BROWSERBASE",
  apiKey: process.env.BROWSERBASE_API_KEY,
  projectId: process.env.BROWSERBASE_PROJECT_ID,
  browserbaseSessionCreateParams: {
    browserSettings: {
      // Optimize for speed
      blockAds: true, // Faster page loads
      solveCaptchas: true, // Auto-solve captchas
    },
    proxies: true, // Use optimized routing
  },
});
Benefits:
  • Pre-warmed browsers
  • Optimized network routing
  • Parallel execution support
  • No local resource constraints

Reduce Logging Overhead

const stagehand = new Stagehand({
  verbose: 0, // Minimal logging
  logInferenceToFile: false, // Don't persist logs
});
Performance impact:
  • verbose: 0 - No console output (fastest)
  • verbose: 1 - Basic logs (~5-10ms overhead)
  • verbose: 2 - Detailed logs (~20-50ms overhead)

Parallel Execution

Run independent operations concurrently:
// ❌ Sequential: ~6 seconds
const page1Data = await stagehand.extract("get title", { page: page1 });
const page2Data = await stagehand.extract("get title", { page: page2 });
const page3Data = await stagehand.extract("get title", { page: page3 });

// ✅ Parallel: ~2 seconds
const [page1Data, page2Data, page3Data] = await Promise.all([
  stagehand.extract("get title", { page: page1 }),
  stagehand.extract("get title", { page: page2 }),
  stagehand.extract("get title", { page: page3 }),
]);

Multiple Stagehand Instances

For heavy workloads, use multiple instances:
const instances = await Promise.all(
  Array.from({ length: 5 }, () => {
    const sh = new Stagehand({ env: "BROWSERBASE" });
    return sh.init().then(() => sh);
  })
);

// Process 5 tasks in parallel
const results = await Promise.all(
  instances.map((sh, i) =>
    sh.extract(`task ${i}`)
  )
);

// Cleanup
await Promise.all(instances.map(sh => sh.close()));

Stream Agent Responses

Get results as they arrive:
const agent = stagehand.agent({
  stream: true, // Enable streaming
});

const run = await agent.execute({
  instruction: "search for products",
  maxSteps: 10,
});

// Process results incrementally
for await (const chunk of run.textStream) {
  console.log(chunk); // Display progress in real-time
}

const finalResult = await run.result;
Benefits:
  • Perceived latency reduction
  • Real-time progress updates
  • Better user experience

Optimize Network Requests

Block Unnecessary Resources

const page = stagehand.context.pages()[0];

// Block images, fonts, and other heavy resources
await page.route("**/*", (route) => {
  const resourceType = route.request().resourceType();
  if (["image", "font", "stylesheet"].includes(resourceType)) {
    route.abort();
  } else {
    route.continue();
  }
});
Blocking resources can break some websites. Test thoroughly.

Reuse Browser Sessions

With Browserbase

// Create a session and keep it alive
const stagehand1 = new Stagehand({
  env: "BROWSERBASE",
  keepAlive: true,
});
await stagehand1.init();

const sessionId = stagehand1.browserbaseSessionID;

// Reuse the session later (saves ~2-3 seconds)
const stagehand2 = new Stagehand({
  env: "BROWSERBASE",
  browserbaseSessionID: sessionId,
});
await stagehand2.init(); // Reconnects to existing session

With Local Browsers

const stagehand = new Stagehand({
  env: "LOCAL",
  localBrowserLaunchOptions: {
    headless: true, // Faster than headed mode
  },
});

await stagehand.init();

// Keep the instance alive for multiple operations
await stagehand.act("task 1");
await stagehand.act("task 2");
await stagehand.act("task 3");

await stagehand.close();

Performance Benchmarks

Typical operation times:
OperationCachedUncachedOptimization
act()50-100ms1-3sUse cache
extract()50-100ms1-4sUse cache
observe()50-100ms1-3sUse cache
agent.execute() (5 steps)200-500ms5-15sUse cache + limit steps
Browser launchN/A2-5sReuse sessions

Profiling Performance

const start = Date.now();

await stagehand.act("click button");

const duration = Date.now() - start;
console.log(`Operation took ${duration}ms`);

Performance Checklist

1

Enable caching

Set cacheDir in Stagehand options
2

Choose appropriate model

Use mini models for simple tasks
3

Set reasonable timeouts

Don’t wait longer than necessary
4

Minimize logging

Use verbose: 0 in production
5

Parallelize when possible

Use Promise.all() for independent operations
6

Reuse browser sessions

Avoid re-launching browsers

Build docs developers (and LLMs) love