Skip to main content
Stagehand supports a wide range of LLM providers through the AI SDK and native clients. You can use models from OpenAI, Anthropic, Google, and many other providers, or integrate your own custom models.

Overview

Stagehand’s LLM system:
  • Multi-provider support - OpenAI, Anthropic, Google, Groq, Cerebras, and more
  • AI SDK integration - Use any AI SDK-compatible provider
  • Native clients - Optimized clients for major providers
  • Custom models - Bring your own model via AI SDK
  • Provider routing - Automatic client selection based on model name
Location: packages/core/lib/v3/llm/

Supported Providers

Native Clients

Stagehand includes optimized native clients for: OpenAI (OpenAIClient.ts):
const stagehand = new Stagehand({
  model: "openai/gpt-4o",
  apiKey: process.env.OPENAI_API_KEY,
});
Anthropic (AnthropicClient.ts):
const stagehand = new Stagehand({
  model: "anthropic/claude-3-7-sonnet-latest",
  apiKey: process.env.ANTHROPIC_API_KEY,
});
Google (GoogleClient.ts):
const stagehand = new Stagehand({
  model: "google/gemini-2.5-flash-preview",
  apiKey: process.env.GEMINI_API_KEY,
});
Groq (GroqClient.ts):
const stagehand = new Stagehand({
  model: "groq/llama-3.3-70b-versatile",
  apiKey: process.env.GROQ_API_KEY,
});
Cerebras (CerebrasClient.ts):
const stagehand = new Stagehand({
  model: "cerebras/cerebras-llama-3.3-70b",
  apiKey: process.env.CEREBRAS_API_KEY,
});

AI SDK Providers

Location: packages/core/lib/v3/llm/LLMProvider.ts Stagehand supports all AI SDK providers:
const AISDKProviders: Record<string, AISDKProvider> = {
  openai,
  bedrock,
  anthropic,
  google,
  xai,
  azure,
  groq,
  cerebras,
  togetherai,
  mistral,
  deepseek,
  perplexity,
  ollama,
  vertex,
  gateway,
};
Example usage:
// Together AI
const stagehand = new Stagehand({
  model: "togetherai/meta-llama/Llama-3.3-70B-Instruct-Turbo",
  apiKey: process.env.TOGETHER_API_KEY,
});

// Mistral
const stagehand = new Stagehand({
  model: "mistral/mistral-large-latest",
  apiKey: process.env.MISTRAL_API_KEY,
});

// DeepSeek
const stagehand = new Stagehand({
  model: "deepseek/deepseek-chat",
  apiKey: process.env.DEEPSEEK_API_KEY,
});

// Perplexity
const stagehand = new Stagehand({
  model: "perplexity/llama-3.1-sonar-large-128k-online",
  apiKey: process.env.PERPLEXITY_API_KEY,
});

Model Format

Use the provider/model format:
// ✓ Correct
"anthropic/claude-sonnet-4-5"
"openai/gpt-4o"
"google/gemini-2.5-flash-preview"
"groq/llama-3.3-70b-versatile"

// ✗ Deprecated (still works but shows warning)
"claude-3-5-sonnet-latest"
"gpt-4o"
"gemini-2.0-flash"

LLM Provider System

Location: packages/core/lib/v3/llm/LLMProvider.ts

Getting a Client

export class LLMProvider {
  private logger: (message: LogLine) => void;

  constructor(logger: (message: LogLine) => void) {
    this.logger = logger;
  }

  getClient(
    modelName: AvailableModel,
    clientOptions?: ClientOptions,
    options?: { experimental?: boolean; disableAPI?: boolean },
  ): LLMClient {
    // Handle provider/model format
    if (modelName.includes("/")) {
      const firstSlashIndex = modelName.indexOf("/");
      const subProvider = modelName.substring(0, firstSlashIndex);
      const subModelName = modelName.substring(firstSlashIndex + 1);

      // Get AI SDK language model
      const languageModel = getAISDKLanguageModel(
        subProvider,
        subModelName,
        clientOptions,
      );

      return new AISdkClient({
        model: languageModel,
        logger: this.logger,
      });
    }

    // Handle deprecated format
    const provider = modelToProviderMap[modelName];
    switch (provider) {
      case "openai":
        return new OpenAIClient({ logger, modelName, clientOptions });
      case "anthropic":
        return new AnthropicClient({ logger, modelName, clientOptions });
      // ...
    }
  }
}

AI SDK Language Model

export function getAISDKLanguageModel(
  subProvider: string,
  subModelName: string,
  clientOptions?: ClientOptions,
) {
  const hasValidOptions =
    clientOptions &&
    Object.values(clientOptions).some((v) => v !== undefined && v !== null);

  if (hasValidOptions) {
    const creator = AISDKProvidersWithAPIKey[subProvider];
    const provider = creator(clientOptions);
    return provider(subModelName);
  } else {
    const provider = AISDKProviders[subProvider];
    return provider(subModelName);
  }
}

Using Custom Models

Via AI SDK Provider

Location: packages/core/examples/custom_client_aisdk.ts
import { Stagehand } from "@browserbasehq/stagehand";
import { createOpenAI } from "@ai-sdk/openai";

const customOpenAI = createOpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: "https://your-custom-endpoint.com/v1",
});

const stagehand = new Stagehand({
  env: "LOCAL",
  model: customOpenAI("your-custom-model"),
});

await stagehand.init();

// Use as normal
const result = await stagehand.extract("extract the page title", {
  title: z.string(),
});

Via Custom OpenAI Client

Location: packages/core/examples/custom_client_openai.ts
import OpenAI from "openai";
import { Stagehand } from "@browserbasehq/stagehand";

const customClient = new OpenAI({
  apiKey: process.env.CUSTOM_API_KEY,
  baseURL: "https://your-custom-endpoint.com/v1",
});

const stagehand = new Stagehand({
  env: "LOCAL",
  llmClient: customClient,
});

await stagehand.init();

Via LangChain

Location: packages/core/examples/custom_client_langchain.ts
import { ChatOpenAI } from "@langchain/openai";
import { Stagehand } from "@browserbasehq/stagehand";

const langchainModel = new ChatOpenAI({
  modelName: "gpt-4o",
  openAIApiKey: process.env.OPENAI_API_KEY,
  temperature: 0,
});

const stagehand = new Stagehand({
  env: "LOCAL",
  llmClient: langchainModel,
});

await stagehand.init();

LLM Client Interface

Location: packages/core/lib/v3/llm/LLMClient.ts

Base Client

export abstract class LLMClient {
  public type: "openai" | "anthropic" | "cerebras" | "groq" | (string & {});
  public modelName: AvailableModel | (string & {});
  public hasVision: boolean;
  public clientOptions: ClientOptions;
  public userProvidedInstructions?: string;

  constructor(modelName: AvailableModel, userProvidedInstructions?: string) {
    this.modelName = modelName;
    this.userProvidedInstructions = userProvidedInstructions;
  }

  abstract createChatCompletion<T>(
    options: CreateChatCompletionOptions,
  ): Promise<T>;

  // AI SDK methods
  public generateObject = generateObject;
  public generateText = generateText;
  public streamText = streamText;
  public streamObject = streamObject;
  public generateImage = experimental_generateImage;
  public embed = embed;
  public embedMany = embedMany;
  public transcribe = experimental_transcribe;
  public generateSpeech = experimental_generateSpeech;

  getLanguageModel?(): LanguageModelV2;
}

Chat Completion Options

export interface ChatCompletionOptions {
  messages: ChatMessage[];
  temperature?: number;
  top_p?: number;
  frequency_penalty?: number;
  presence_penalty?: number;
  image?: {
    buffer: Buffer;
    description?: string;
  };
  response_model?: {
    name: string;
    schema: StagehandZodSchema;
  };
  tools?: LLMTool[];
  tool_choice?: "auto" | "none" | "required";
  maxOutputTokens?: number;
  requestId?: string;
}

Usage

const llmClient = provider.getClient(modelName, clientOptions);

const response = await llmClient.createChatCompletion({
  logger: this.logger,
  options: {
    messages: [
      { role: "system", content: systemPrompt },
      { role: "user", content: userMessage },
    ],
    response_model: {
      name: "ExtractionResult",
      schema: extractionSchema,
    },
  },
});

Custom Client Options

Base URL Override

const stagehand = new Stagehand({
  model: "openai/gpt-4o",
  modelClientOptions: {
    apiKey: process.env.OPENAI_API_KEY,
    baseURL: "https://your-proxy.com/v1",
  },
});

Organization ID

const stagehand = new Stagehand({
  model: "openai/gpt-4o",
  modelClientOptions: {
    apiKey: process.env.OPENAI_API_KEY,
    organization: process.env.OPENAI_ORG_ID,
  },
});

Custom Headers

const stagehand = new Stagehand({
  model: "openai/gpt-4o",
  modelClientOptions: {
    apiKey: process.env.OPENAI_API_KEY,
    defaultHeaders: {
      "X-Custom-Header": "value",
    },
  },
});

Ollama Integration

Local Models

import { Stagehand } from "@browserbasehq/stagehand";

const stagehand = new Stagehand({
  model: "ollama/llama3.3",
  modelClientOptions: {
    baseURL: "http://localhost:11434",
  },
});

await stagehand.init();

Vision Models

const stagehand = new Stagehand({
  model: "ollama/llava",
  modelClientOptions: {
    baseURL: "http://localhost:11434",
  },
});

// Extract with vision
const result = await stagehand.extract("what's in this image?", schema);

Agent Model Configuration

Per-Agent Models

const agent = stagehand.agent({
  model: {
    modelName: "anthropic/claude-sonnet-4-5",
    apiKey: process.env.ANTHROPIC_API_KEY,
  },
});

Execution Models

Use different models for tool execution:
const agent = stagehand.agent({
  model: "openai/gpt-4o", // Main agent model
  executionModel: "openai/gpt-4o-mini", // Tool execution model (faster/cheaper)
});
Or per-tool:
const result = await stagehand.act("click the button", {
  model: {
    modelName: "anthropic/claude-haiku-3-5",
    apiKey: process.env.ANTHROPIC_API_KEY,
  },
});

Model Capabilities

Vision Support

Models with vision capabilities:
  • openai/gpt-4o
  • anthropic/claude-3-5-sonnet-*
  • google/gemini-2.5-*
  • ollama/llava

Structured Outputs

Models with native structured output:
  • openai/gpt-4o-2024-08-06
  • anthropic/claude-3-*
  • google/gemini-2.5-*

Function Calling

All major providers support function calling:
  • OpenAI (via tools)
  • Anthropic (via tool_use)
  • Google (via functionDeclarations)
  • Groq (via tools)

Best Practices

  1. Use provider/model format: More explicit and future-proof
  2. Match model to task: Fast models for simple tasks, capable models for complex
  3. Test with multiple providers: Different strengths for different tasks
  4. Monitor costs: Track token usage across providers
  5. Use execution models: Save costs on tool executions
  6. Cache when possible: Reuse clients and leverage prompt caching
  7. Handle errors gracefully: Implement fallbacks for provider issues

Error Handling

try {
  const stagehand = new Stagehand({
    model: "provider/model-name",
    modelClientOptions: { apiKey: process.env.API_KEY },
  });
  await stagehand.init();
} catch (error) {
  if (error instanceof UnsupportedAISDKModelProviderError) {
    console.error("Provider not supported:", error.message);
    // Fallback to different provider
  } else if (error instanceof ExperimentalNotConfiguredError) {
    console.error("Enable experimental mode:", error.message);
  }
}

Performance Comparison

Fast models (for simple tasks):
  • openai/gpt-4o-mini - Very fast, low cost
  • google/gemini-2.0-flash-lite - Extremely fast
  • groq/llama-3.3-70b-specdec - Fastest inference
  • anthropic/claude-haiku-3-5 - Fast and capable
Balanced models:
  • openai/gpt-4o - Good balance
  • google/gemini-2.5-flash-preview - Fast with good quality
  • anthropic/claude-3-5-sonnet-* - High quality, reasonable speed
Capable models (for complex tasks):
  • openai/o1 - Reasoning tasks
  • anthropic/claude-3-7-sonnet-latest - Best overall quality
  • google/gemini-2.5-pro-preview - Long context, high quality

References

  • LLM Provider: packages/core/lib/v3/llm/LLMProvider.ts
  • LLM Client: packages/core/lib/v3/llm/LLMClient.ts
  • AI SDK Client: packages/core/lib/v3/llm/aisdk.ts
  • OpenAI Client: packages/core/lib/v3/llm/OpenAIClient.ts
  • Anthropic Client: packages/core/lib/v3/llm/AnthropicClient.ts
  • Google Client: packages/core/lib/v3/llm/GoogleClient.ts
  • Custom Client Examples: packages/core/examples/custom_client_*.ts

Build docs developers (and LLMs) love