Skip to main content
Stagehand performance depends on several factors: DOM processing speed, LLM inference time, browser operations, and network latency. This guide provides proven strategies to maximize automation speed.

Quick Performance Wins

1. Plan Ahead with Observe

Use a single observe() call to plan multiple actions, then execute them efficiently:
// Instead of sequential operations with multiple LLM calls
await stagehand.act("Fill name field");        // LLM call #1
await stagehand.act("Fill email field");       // LLM call #2
await stagehand.act("Select country dropdown"); // LLM call #3

// Use single observe to plan all form fields - one LLM call
const formFields = await stagehand.observe("Find all form fields to fill");

// Execute all actions without LLM inference
for (const field of formFields) {
  await stagehand.act(field); // No LLM calls!
}
Performance Tip: Acting on observe results avoids LLM inference entirely. This approach is 2-3x faster than direct act() calls and is the recommended pattern for multi-step workflows.

Caching Guide

Learn advanced caching patterns and cache invalidation strategies

2. Optimize DOM Processing

Reduce DOM complexity before Stagehand processes the page:
// Remove heavy elements that slow down processing
await page.evaluate(() => {
  // Remove video elements
  document.querySelectorAll('video, iframe').forEach(el => el.remove());
  
  // Hide complex animations
  document.querySelectorAll('[style*="animation"]').forEach(el => {
    (el as HTMLElement).style.animation = 'none';
  });
});

// Then perform Stagehand operations
await stagehand.act("Click the submit button");

3. Set Appropriate Timeouts

Use shorter timeouts for simple operations and longer ones for complex page loads:
// Simple actions - reduce action timeout
await stagehand.act("Click the login button", {
  timeout: 5000  // Default is 30000ms, reduce for simple clicks
});

// Complex page loads - optimize navigation
const page = stagehand.context.pages()[0];
await page.goto("https://heavy-spa.com", {
  waitUntil: "domcontentloaded", // Don't wait for all resources
  timeout: 15000 // Shorter than default 30s
});

Performance Monitoring and Benchmarking

Track performance metrics and measure optimization impact:

Performance Tracking

class PerformanceTracker {
  private speedMetrics: Map<string, number[]> = new Map();

  async timedAct(page: Page, prompt: string): Promise<ActResult> {
    const start = Date.now();
    const result = await stagehand.act(prompt);
    const duration = Date.now() - start;
    
    if (!this.speedMetrics.has(prompt)) {
      this.speedMetrics.set(prompt, []);
    }
    this.speedMetrics.get(prompt)!.push(duration);
    
    console.log(`Action "${prompt}" took ${duration}ms`);
    return result;
  }

  getAverageTime(prompt: string): number {
    const times = this.speedMetrics.get(prompt) || [];
    return times.reduce((a, b) => a + b, 0) / times.length;
  }
}
Example Output:
Action "Fill form" took 1000ms
Action "Click submit" took 2000ms
Action "Confirm submission" took 5000ms

Before vs After Benchmarking

// Before optimization
console.time("workflow");
await stagehand.act("Fill form");
await stagehand.act("Click submit");
await stagehand.act("Confirm submission");
console.timeEnd("workflow"); // 8000ms

// After optimization with observe planning
console.time("workflow-optimized");
const workflowActions = await stagehand.observe("Find form, submit, and confirm elements");

// Execute actions sequentially to avoid conflicts
for (const action of workflowActions) {
  await stagehand.act(action);
}
console.timeEnd("workflow-optimized"); // 500ms
Example Output:
Workflow took 8000ms
Optimized workflow took 500ms