AgentSkillsCN

functions

指导用户使用官方 Browserbase Functions CLI 部署无服务器浏览器自动化。适用于用户希望按计划部署自动化任务、需要为浏览器自动化设置 Webhook 端点、希望在云端运行自动化,或咨询 Browserbase Functions 相关问题时使用。

SKILL.md
--- frontmatter
name: functions
description: Guide deployment of serverless browser automation using the official Browserbase Functions CLI. Use when the user wants to deploy automation to run on a schedule, needs a webhook endpoint for browser automation, wants to run automation in the cloud, or asks about Browserbase Functions.

Browserbase Functions

Deploy serverless browser automation to the cloud using the official bb CLI.

When to Use

  • 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

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:

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

2. Add Credentials to .env

bash
echo "BROWSERBASE_API_KEY=$BROWSERBASE_API_KEY" >> .env
echo "BROWSERBASE_PROJECT_ID=$BROWSERBASE_PROJECT_ID" >> .env

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.

Deploying

Publish to Browserbase

bash
pnpm bb publish index.ts

Save the Function ID from the output -- 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) {
  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();

  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]!;

  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');

  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

CommandDescription
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
cat .env    # Check credentials exist
export BROWSERBASE_API_KEY="your_key"
export BROWSERBASE_PROJECT_ID="your_project"

Dev server won't start

bash
pnpm add @browserbasehq/sdk-functions

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
  • Use chromium.connectOverCDP() not chromium.launch()