functions

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Browserbase Functions Skill

Browserbase Functions 技能

Guide Claude through deploying serverless browser automation using the official
bb
CLI.
指导你使用官方
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
在以下场景使用本技能:
  • 用户想要部署可按计划运行的自动化任务
  • 用户需要用于浏览器自动化的Webhook端点
  • 用户希望在云端(而非本地)运行自动化任务
  • 用户询问Browserbase Functions相关内容

Prerequisites

前置条件

1. Get Credentials

1. 获取凭证

Get API key and Project ID from: https://browserbase.com/settings
从以下地址获取API密钥和项目ID:https://browserbase.com/settings

2. Set Environment Variables

2. 设置环境变量

Set directly:
bash
export BROWSERBASE_API_KEY="your_api_key"
export BROWSERBASE_PROJECT_ID="your_project_id"
直接设置:
bash
export BROWSERBASE_API_KEY="your_api_key"
export BROWSERBASE_PROJECT_ID="your_project_id"

Creating a Function Project

创建函数项目

1. Initialize with Official CLI

1. 使用官方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
bash
pnpm dlx @browserbasehq/sdk-functions init my-function
cd my-function
此命令会创建如下结构:
my-function/
├── package.json
├── index.ts        # 你的函数代码
└── .env            # 在此添加凭证

2. Add Credentials to .env

2. 将凭证添加到.env文件

bash
undefined
bash
undefined

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
undefined
echo "BROWSERBASE_API_KEY=$BROWSERBASE_API_KEY" >> .env echo "BROWSERBASE_PROJECT_ID=$BROWSERBASE_PROJECT_ID" >> .env

或者手动编辑`.env`:
BROWSERBASE_API_KEY=your_api_key BROWSERBASE_PROJECT_ID=your_project_id
undefined

3. Install Dependencies

3. 安装依赖

bash
pnpm install
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
typescript
import { defineFn } from "@browserbasehq/sdk-functions";
import { chromium } from "playwright-core";

defineFn("my-function", async (context) => {
  const { session, params } = context;
  
  // 连接到浏览器
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;
  
  // 你的自动化逻辑
  await page.goto(params.url || "https://example.com");
  const title = await page.title();
  
  // 返回可序列化为JSON的结果
  return { success: true, title };
});
关键对象:
  • context.session.connectUrl
    - 用于连接Playwright的CDP端点
  • context.params
    - 调用时传入的输入参数

Development Workflow

开发工作流

1. Start Dev Server

1. 启动开发服务器

bash
pnpm bb dev index.ts
Server runs at
http://127.0.0.1:14113
bash
pnpm bb dev index.ts
服务器运行在
http://127.0.0.1:14113

2. Test Locally

2. 本地测试

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"}}'
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

3. 迭代开发

The dev server auto-reloads on file changes. Use
console.log()
for debugging - output appears in the terminal.
开发服务器会在文件变更时自动重载。使用
console.log()
进行调试,输出会显示在终端中。

Deploying

部署

Publish to Browserbase

发布到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.
bash
pnpm bb publish index.ts
输出示例:
Function published successfully
Build ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Function ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
请保存Function ID - 调用函数时需要用到它。

Invoking Deployed Functions

调用已部署的函数

Via curl

使用curl

bash
undefined
bash
undefined

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"}}'
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"}

响应: {"id": "INVOCATION_ID"}

Poll for result

轮询获取结果

curl "https://api.browserbase.com/v1/functions/invocations/INVOCATION_ID"
-H "x-bb-api-key: $BROWSERBASE_API_KEY"
undefined
curl "https://api.browserbase.com/v1/functions/invocations/INVOCATION_ID"
-H "x-bb-api-key: $BROWSERBASE_API_KEY"
undefined

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

CLI 参考

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
命令描述
pnpm dlx @browserbasehq/sdk-functions init <name>
创建新项目
pnpm bb dev <file>
启动本地开发服务器
pnpm bb publish <file>
部署到Browserbase

Troubleshooting

故障排除

"Missing API key"

"Missing API key"(缺少API密钥)

bash
undefined
bash
undefined

Check .env file has credentials

检查.env文件是否包含凭证

cat .env
cat .env

Or set for current shell

或者为当前Shell设置环境变量

export BROWSERBASE_API_KEY="your_key" export BROWSERBASE_PROJECT_ID="your_project"
undefined
export BROWSERBASE_API_KEY="your_key" export BROWSERBASE_PROJECT_ID="your_project"
undefined

Dev server won't start

开发服务器无法启动

bash
undefined
bash
undefined

Make sure SDK is installed

确保已安装SDK

pnpm add @browserbasehq/sdk-functions
pnpm add @browserbasehq/sdk-functions

Or use npx

或者使用npx

npx @browserbasehq/sdk-functions dev index.ts
undefined
npx @browserbasehq/sdk-functions dev index.ts
undefined

Function times out

函数超时

  • Max execution time is 15 minutes
  • Add specific timeouts to page operations
  • Use
    waitForSelector
    instead of sleep
  • 最大执行时间为15分钟
  • 为页面操作添加特定的超时设置
  • 使用
    waitForSelector
    而非sleep

Can't connect to browser

无法连接到浏览器

  • Check
    session.connectUrl
    is being used correctly
  • Ensure you're using
    chromium.connectOverCDP()
    not
    chromium.launch()
  • 检查
    session.connectUrl
    是否正确使用
  • 确保你使用的是
    chromium.connectOverCDP()
    而非
    chromium.launch()