home / skills / browserbase / skills-old / functions

functions skill

/skills/functions

This skill guides you to deploy serverless browser automation with the official bb CLI, including setup, development, and invocation.

This is most likely a fork of the functions skill from openclaw
npx playbooks add skill browserbase/skills-old --skill functions

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
6.7 KB
---
name: functions
description: Guide Claude through deploying serverless browser automation using the official bb CLI
---

# Browserbase Functions Skill

Guide Claude through deploying serverless browser automation using the official `bb` CLI.

## When to Use

Use this skill when:
- User wants to deploy automation to run on a schedule
- User needs a webhook endpoint for browser automation
- User wants to run automation in the cloud (not locally)
- User asks about Browserbase Functions

## Prerequisites

### 1. Get Credentials

Get API key and Project ID from: https://browserbase.com/settings

### 2. Set Environment Variables

Set directly:
```bash
export BROWSERBASE_API_KEY="your_api_key"
export BROWSERBASE_PROJECT_ID="your_project_id"
```

## Creating a Function Project

### 1. Initialize with Official CLI

```bash
pnpm dlx @browserbasehq/sdk-functions init my-function
cd my-function
```

This creates:
```
my-function/
├── package.json
├── index.ts        # Your function code
└── .env            # Add credentials here
```

### 2. Add Credentials to .env

```bash
# Copy from stored credentials
echo "BROWSERBASE_API_KEY=$BROWSERBASE_API_KEY" >> .env
echo "BROWSERBASE_PROJECT_ID=$BROWSERBASE_PROJECT_ID" >> .env
```

Or manually edit `.env`:
```
BROWSERBASE_API_KEY=your_api_key
BROWSERBASE_PROJECT_ID=your_project_id
```

### 3. Install Dependencies

```bash
pnpm install
```

## Function Structure

```typescript
import { defineFn } from "@browserbasehq/sdk-functions";
import { chromium } from "playwright-core";

defineFn("my-function", async (context) => {
  const { session, params } = context;
  
  // Connect to browser
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;
  
  // Your automation
  await page.goto(params.url || "https://example.com");
  const title = await page.title();
  
  // Return JSON-serializable result
  return { success: true, title };
});
```

**Key objects:**
- `context.session.connectUrl` - CDP endpoint to connect Playwright
- `context.params` - Input parameters from invocation

## Development Workflow

### 1. Start Dev Server

```bash
pnpm bb dev index.ts
```

Server runs at `http://127.0.0.1:14113`

### 2. Test Locally

```bash
curl -X POST http://127.0.0.1:14113/v1/functions/my-function/invoke \
  -H "Content-Type: application/json" \
  -d '{"params": {"url": "https://news.ycombinator.com"}}'
```

### 3. Iterate

The dev server auto-reloads on file changes. Use `console.log()` for debugging - output appears in the terminal.

## Deploying

### Publish to Browserbase

```bash
pnpm bb publish index.ts
```

Output:
```
Function published successfully
Build ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Function ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

**Save the Function ID** - you need it to invoke.

## Invoking Deployed Functions

### Via curl

```bash
# Start invocation
curl -X POST "https://api.browserbase.com/v1/functions/FUNCTION_ID/invoke" \
  -H "Content-Type: application/json" \
  -H "x-bb-api-key: $BROWSERBASE_API_KEY" \
  -d '{"params": {"url": "https://example.com"}}'

# Response: {"id": "INVOCATION_ID"}

# Poll for result
curl "https://api.browserbase.com/v1/functions/invocations/INVOCATION_ID" \
  -H "x-bb-api-key: $BROWSERBASE_API_KEY"
```

### Via Code

```typescript
async function invokeFunction(functionId: string, params: object) {
  // Start invocation
  const invokeRes = await fetch(
    `https://api.browserbase.com/v1/functions/${functionId}/invoke`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-bb-api-key': process.env.BROWSERBASE_API_KEY!,
      },
      body: JSON.stringify({ params }),
    }
  );
  const { id: invocationId } = await invokeRes.json();

  // Poll until complete
  while (true) {
    await new Promise(r => setTimeout(r, 5000));
    
    const statusRes = await fetch(
      `https://api.browserbase.com/v1/functions/invocations/${invocationId}`,
      { headers: { 'x-bb-api-key': process.env.BROWSERBASE_API_KEY! } }
    );
    const result = await statusRes.json();
    
    if (result.status === 'COMPLETED') return result.results;
    if (result.status === 'FAILED') throw new Error(result.error);
  }
}
```

## Common Patterns

### Parameterized Scraping

```typescript
defineFn("scrape", async ({ session, params }) => {
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;
  
  await page.goto(params.url);
  await page.waitForSelector(params.selector);
  
  const items = await page.$$eval(params.selector, els => 
    els.map(el => el.textContent?.trim())
  );
  
  return { url: params.url, items };
});
```

### With Authentication

```typescript
defineFn("authenticated-action", async ({ session, params }) => {
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;
  
  // Login
  await page.goto("https://example.com/login");
  await page.fill('[name="email"]', params.email);
  await page.fill('[name="password"]', params.password);
  await page.click('button[type="submit"]');
  await page.waitForURL('**/dashboard');
  
  // Do authenticated work
  const data = await page.textContent('.user-data');
  return { data };
});
```

### Error Handling

```typescript
defineFn("safe-scrape", async ({ session, params }) => {
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;
  
  try {
    await page.goto(params.url, { timeout: 30000 });
    await page.waitForSelector(params.selector, { timeout: 10000 });
    
    const data = await page.textContent(params.selector);
    return { success: true, data };
  } catch (error) {
    return { 
      success: false, 
      error: error instanceof Error ? error.message : 'Unknown error' 
    };
  }
});
```

## CLI Reference

| Command | Description |
|---------|-------------|
| `pnpm dlx @browserbasehq/sdk-functions init <name>` | Create new project |
| `pnpm bb dev <file>` | Start local dev server |
| `pnpm bb publish <file>` | Deploy to Browserbase |

## Troubleshooting

### "Missing API key"
```bash
# Check .env file has credentials
cat .env

# Or set for current shell
export BROWSERBASE_API_KEY="your_key"
export BROWSERBASE_PROJECT_ID="your_project"
```

### Dev server won't start
```bash
# Make sure SDK is installed
pnpm add @browserbasehq/sdk-functions

# Or use npx
npx @browserbasehq/sdk-functions dev index.ts
```

### Function times out
- Max execution time is 15 minutes
- Add specific timeouts to page operations
- Use `waitForSelector` instead of sleep

### Can't connect to browser
- Check `session.connectUrl` is being used correctly
- Ensure you're using `chromium.connectOverCDP()` not `chromium.launch()`

Overview

This skill guides you through deploying serverless browser automation using the official bb CLI and the Browserbase Functions SDK. It covers setup, local development, publishing, invocation, and common automation patterns. The instructions focus on Playwright-based automation connected via the provided CDP session endpoint.

How this skill works

You write a function that connects Playwright to the provided session.connectUrl, run and test it locally with the bb dev server, then publish it with pnpm bb publish. Deployed functions are invoked via the Browserbase API (or curl) and return JSON-serializable results. The skill includes patterns for parameterized scraping, authenticated flows, and safe error handling.

When to use it

  • You need cloud-hosted browser automation instead of running locally
  • You want scheduled or webhook-triggered browser jobs
  • You require a stable CDP endpoint for Playwright-based scripts
  • You want a simple development loop with live reload and local testing
  • You need to publish and invoke automation via an API

Best practices

  • Store BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID in a .env or environment variables and never commit them
  • Use context.params for inputs and return JSON-serializable results only
  • Prefer waitForSelector and explicit timeouts over sleeps to reduce flakiness
  • Log to console for local debugging; inspect terminal output from bb dev
  • Handle errors by catching exceptions and returning structured error objects

Example use cases

  • Parameterized scraper that takes a URL and CSS selector and returns extracted items
  • Scheduled data extraction job to snapshot site content every hour
  • Webhook-triggered automation that logs in and performs an authenticated action
  • Headless testing harness that runs browser checks in the cloud and reports results
  • Ad-hoc crawler to gather headlines or product listings without maintaining local infrastructure

FAQ

How do I get API credentials?

Retrieve your API key and Project ID from your Browserbase account settings and export them to BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID.

How do I invoke a published function and get results?

POST to /v1/functions/FUNCTION_ID/invoke with x-bb-api-key, receive an invocation id, then poll /v1/functions/invocations/INVOCATION_ID until status is COMPLETED or FAILED.