Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/browserbase/stagehand/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The Go SDK provides an idiomatic Go interface to Stagehand’s browser automation capabilities. It communicates with the Stagehand API server using Go’s native HTTP client and concurrency patterns.
The Go SDK is currently under development. This page describes the planned architecture and usage patterns. Check the GitHub repository for the latest status.

Architecture

The Go SDK follows the same client-server architecture:
┌─────────────────┐
│   Go Client     │
│   (Your Code)   │
└────────┬────────┘
         │ HTTP/REST

┌─────────────────┐
│  API Server     │
│  (TypeScript)   │
└────────┬────────┘
         │ CDP

┌─────────────────┐
│  Browser        │
│  (Browserbase)  │
└─────────────────┘

Installation

go get github.com/browserbase/stagehand-go

Repository

The Go SDK will be maintained in a dedicated repository:

Go SDK on GitHub

View the Go SDK repository (coming soon)

Quick Start

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/browserbase/stagehand-go"
)

func main() {
    ctx := context.Background()

    // Initialize Stagehand
    config := &stagehand.Config{
        Env:       "BROWSERBASE",
        APIKey:    os.Getenv("BROWSERBASE_API_KEY"),
        ProjectID: os.Getenv("BROWSERBASE_PROJECT_ID"),
        Model: &stagehand.ModelConfig{
            ModelName: "openai/gpt-4o",
            APIKey:    os.Getenv("OPENAI_API_KEY"),
        },
        Verbose: 1,
    }

    client, err := stagehand.New(config)
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    // Initialize session
    if err := client.Init(ctx); err != nil {
        log.Fatal(err)
    }

    // Navigate to a page
    page := client.Page()
    if err := page.Goto(ctx, "https://github.com/browserbase"); err != nil {
        log.Fatal(err)
    }

    // Perform an action
    actResult, err := client.Act(ctx, "click on the stagehand repo", nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Action:", actResult.Message)

    // Extract data
    schema := map[string]interface{}{
        "description": "string",
        "stars":       "number",
    }

    extractResult, err := client.Extract(ctx, 
        "extract the repository details", schema, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Data: %+v\n", extractResult.Data)
}

Core API

Client Configuration

type Config struct {
    Env                string
    APIKey             string
    ProjectID          string
    Model              *ModelConfig
    Verbose            int
    SystemPrompt       string
    SelfHeal           bool
    CacheDir           string
    DOMSettleTimeout   int
    Logger             Logger
}

type ModelConfig struct {
    ModelName   string
    APIKey      string
    BaseURL     string
    Temperature float64
}

Methods

Act()

Execute actions with natural language:
// Simple action
result, err := client.Act(ctx, "click the login button", nil)
if err != nil {
    log.Fatal(err)
}

// With variables
options := &stagehand.ActOptions{
    Variables: map[string]string{
        "email": "user@example.com",
    },
    Timeout: 5000,
}

result, err = client.Act(ctx, 
    "fill the email field with {{email}}", options)

Extract()

Extract structured data:
schema := map[string]interface{}{
    "name":  "string",
    "email": "string",
    "age":   "number",
}

result, err := client.Extract(ctx, 
    "get user information", schema, nil)
if err != nil {
    log.Fatal(err)
}

data := result.Data.(map[string]interface{})
fmt.Println("Name:", data["name"])

Observe()

Find elements without acting:
actions, err := client.Observe(ctx, "find all product cards", nil)
if err != nil {
    log.Fatal(err)
}

for _, action := range actions {
    fmt.Printf("Selector: %s\n", action.Selector)
    fmt.Printf("Description: %s\n", action.Description)
}

Agent.Execute()

Run multi-step autonomous tasks:
agent := client.Agent()

options := &stagehand.AgentExecuteOptions{
    MaxSteps: 10,
}

result, err := agent.Execute(ctx, 
    "Search for Go tutorials and extract the top 3 results", options)
if err != nil {
    log.Fatal(err)
}

fmt.Println("Message:", result.Message)
for _, action := range result.Actions {
    fmt.Printf("Step: %s\n", action.Type)
}

Context Support

The Go SDK fully supports context for cancellation and timeouts:
// With timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

result, err := client.Act(ctx, "click button", nil)
if err != nil {
    if ctx.Err() == context.DeadlineExceeded {
        log.Println("Operation timed out")
    }
}

// With cancellation
ctx, cancel := context.WithCancel(context.Background())

go func() {
    time.Sleep(10 * time.Second)
    cancel()
}()

result, err := client.Extract(ctx, "get data", schema, nil)

Goroutines and Concurrency

The SDK is goroutine-safe for concurrent operations:
var wg sync.WaitGroup
results := make(chan *stagehand.ExtractResult, 3)

urls := []string{
    "https://example1.com",
    "https://example2.com",
    "https://example3.com",
}

for _, url := range urls {
    wg.Add(1)
    go func(u string) {
        defer wg.Done()
        
        // Each goroutine gets its own page
        page := client.NewPage()
        page.Goto(ctx, u)
        
        result, err := client.Extract(ctx, "get title", schema, 
            &stagehand.ExtractOptions{Page: page})
        if err != nil {
            log.Println(err)
            return
        }
        
        results <- result
    }(url)
}

wg.Wait()
close(results)

for result := range results {
    fmt.Printf("%+v\n", result.Data)
}

Examples

Web Scraping

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/browserbase/stagehand-go"
)

func scrapeNews(client *stagehand.Client) error {
    ctx := context.Background()
    
    page := client.Page()
    if err := page.Goto(ctx, "https://news.ycombinator.com"); err != nil {
        return err
    }
    
    schema := map[string]interface{}{
        "articles": []map[string]interface{}{
            {
                "title":  "string",
                "url":    "string",
                "points": "number",
            },
        },
    }
    
    result, err := client.Extract(ctx, 
        "extract the top 5 articles", schema, nil)
    if err != nil {
        return err
    }
    
    data := result.Data.(map[string]interface{})
    articles := data["articles"].([]interface{})
    
    for _, a := range articles {
        article := a.(map[string]interface{})
        fmt.Printf("%s - %.0f points\n", 
            article["title"], article["points"])
    }
    
    return nil
}

func main() {
    client, err := stagehand.New(config)
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
    
    if err := client.Init(context.Background()); err != nil {
        log.Fatal(err)
    }
    
    if err := scrapeNews(client); err != nil {
        log.Fatal(err)
    }
}

Form Automation

func fillForm(client *stagehand.Client, name, email string) error {
    ctx := context.Background()
    
    page := client.Page()
    if err := page.Goto(ctx, "https://example.com/form"); err != nil {
        return err
    }
    
    variables := map[string]string{
        "name":  name,
        "email": email,
    }
    
    if _, err := client.Act(ctx, 
        "fill the name field with {{name}}",
        &stagehand.ActOptions{Variables: variables}); err != nil {
        return err
    }
    
    if _, err := client.Act(ctx,
        "fill the email field with {{email}}",
        &stagehand.ActOptions{Variables: variables}); err != nil {
        return err
    }
    
    if _, err := client.Act(ctx, "click the submit button", nil); err != nil {
        return err
    }
    
    schema := map[string]interface{}{"message": "string"}
    result, err := client.Extract(ctx, 
        "get the success message", schema, nil)
    if err != nil {
        return err
    }
    
    data := result.Data.(map[string]interface{})
    fmt.Println("Result:", data["message"])
    
    return nil
}

Error Handling

import "github.com/browserbase/stagehand-go/errors"

result, err := client.Act(ctx, "click button", nil)
if err != nil {
    switch e := err.(type) {
    case *errors.ActTimeoutError:
        log.Printf("Action timed out: %v", e)
    case *errors.APIError:
        log.Printf("API error: %v", e)
    case *errors.NetworkError:
        log.Printf("Network error: %v", e)
    default:
        log.Printf("Unknown error: %v", e)
    }
}

Type Safety with Generics

Use Go generics for type-safe extraction:
type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Age   int    `json:"age"`
}

schema := map[string]interface{}{
    "name":  "string",
    "email": "string",
    "age":   "number",
}

var user User
if err := client.ExtractTyped(ctx, "get user info", schema, &user, nil); err != nil {
    log.Fatal(err)
}

fmt.Println(user.Name, user.Email, user.Age)

Logging

Custom logger interface:
type Logger interface {
    Debug(msg string, fields ...interface{})
    Info(msg string, fields ...interface{})
    Warn(msg string, fields ...interface{})
    Error(msg string, fields ...interface{})
}

// Use with your favorite logger (logrus, zap, etc.)
config := &stagehand.Config{
    Logger: myLogger,
    // ...
}

Working with the API Server

The Go SDK requires the Stagehand API server:
// Use Browserbase hosted API
config := &stagehand.Config{
    Env:       "BROWSERBASE",
    APIKey:    os.Getenv("BROWSERBASE_API_KEY"),
    ProjectID: os.Getenv("BROWSERBASE_PROJECT_ID"),
}

// Or custom endpoint
config := &stagehand.Config{
    Env:    "LOCAL",
    APIURL: "http://localhost:3000",
}

Resources

Go SDK Repository

Source code (coming soon)

TypeScript SDK

Reference implementation

pkg.go.dev

Browse Go packages

API Documentation

Full API reference

Contributing

Interested in contributing to the Go SDK?

Build docs developers (and LLMs) love