# How to Deploy Serverless Browser Automation with Browserbase Functions

> Deploy serverless browser automation with Browserbase Functions. Scaffold, develop locally, and publish your Playwright scripts as cloud functions for easy REST API invocation.

- Repository: [browserbase/skills](https://github.com/browserbase/skills)
- Tags: how-to-guide
- Published: 2026-05-01

---

**Browserbase Functions let you package Playwright-driven browser automation as a serverless cloud function by using the `@browserbasehq/sdk-functions` CLI to scaffold, develop locally with `pnpm bb dev`, and deploy with `pnpm bb publish` to obtain a Function ID for invocation via REST API.**

If you need to run browser automation at scale without managing infrastructure, Browserbase Functions offer a managed solution within the browserbase/skills ecosystem. This guide walks through the complete workflow to deploy serverless browser automation with Browserbase Functions, from project initialization to production invocation.

## What Are Browserbase Functions?

Browserbase Functions are serverless cloud functions specifically designed for browser automation workloads. According to [`skills/functions/SKILL.md`](https://github.com/browserbase/skills/blob/main/skills/functions/SKILL.md), these functions wrap Playwright scripts inside a containerized environment hosted by Browserbase, allowing you to execute scraping, testing, or interaction tasks on demand without provisioning servers.

The architecture centers on three core components:

- **`@browserbasehq/sdk-functions`**: The CLI and runtime library that packages your code.
- **`defineFn`**: The registration function that exposes your automation logic.
- **`context.session.connectUrl`**: A secure Chrome DevTools Protocol (CDP) endpoint providing access to a remote Chromium instance.

## Prerequisites and Project Initialization

Before writing code, scaffold a new function project using the Browserbase SDK.

### Installing the SDK

Initialize a new project using your preferred package manager. The CLI generates a minimal Node.js/TypeScript structure:

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

```

This creates [`package.json`](https://github.com/browserbase/skills/blob/main/package.json), a template [`index.ts`](https://github.com/browserbase/skills/blob/main/index.ts) entry file, and a `.env` placeholder for credentials.

### Project Structure

The generated layout follows serverless function conventions:

- **[`index.ts`](https://github.com/browserbase/skills/blob/main/index.ts)**: Your function implementation where Playwright automation lives.
- **`.env`**: Stores `BROWSERBASE_API_KEY` and `BROWSERBASE_PROJECT_ID` (never commit this file).
- **[`package.json`](https://github.com/browserbase/skills/blob/main/package.json)**: Declares the `@browserbasehq/sdk-functions` dependency.

Configure your credentials immediately after scaffolding:

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

```

## Implementing Your Function

Implementation occurs inside [`index.ts`](https://github.com/browserbase/skills/blob/main/index.ts), where you register an async handler that receives a managed browser session.

### The defineFn Handler

Use `defineFn` from `@browserbasehq/sdk-functions` to register your function name and handler:

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

defineFn("scrape-title", async ({ session, params }) => {
  // Handler implementation
});

```

The handler receives a `context` object containing:

- **`session.connectUrl`**: The CDP endpoint for the remote browser.
- **`params`**: Custom arguments passed during invocation.

### Connecting to the Browser Session

Inside the handler, connect to the remote Chromium instance using `chromium.connectOverCDP`. The function must return a JSON-serializable value:

```typescript
defineFn("scrape-title", async ({ session, params }) => {
  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();

  return { success: true, title };
});

```

The SDK automatically serializes the return value and stores it as the invocation payload, as documented in [`skills/functions/SKILL.md`](https://github.com/browserbase/skills/blob/main/skills/functions/SKILL.md).

## Local Development and Testing

Test your function locally before deploying to production. Run the development server:

```bash
pnpm bb dev index.ts

```

This exposes a temporary HTTP endpoint at `http://127.0.0.1:14113`. Test your function using `curl`:

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

```

Local development validates your Playwright logic without consuming remote Browserbase resources.

## Deploying to Browserbase

When ready for production, publish your function:

```bash
pnpm bb publish index.ts

```

This command builds a container image, uploads it to Browserbase, and returns a **Function ID**. This ID serves as the permanent reference for your deployed serverless function.

The deployment process compiles your TypeScript, bundles dependencies, and configures the runtime environment according to specifications in [`skills/functions/SKILL.md`](https://github.com/browserbase/skills/blob/main/skills/functions/SKILL.md).

## Invoking Deployed Functions

Once deployed, invoke your function from any environment using the Browserbase REST API. Replace `<FUNCTION_ID>` with the ID returned during publishing:

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

```

The API returns an invocation ID that you can poll to retrieve results. For detailed invocation patterns and error handling, refer to [`skills/functions/REFERENCE.md`](https://github.com/browserbase/skills/blob/main/skills/functions/REFERENCE.md).

## Summary

- **Browserbase Functions** package Playwright scripts as serverless cloud functions using the `@browserbasehq/sdk-functions` SDK.
- **Project setup** requires running `pnpm dlx @browserbasehq/sdk-functions init` and configuring `.env` with your API credentials.
- **Implementation** uses `defineFn` to register handlers that connect to remote browsers via `chromium.connectOverCDP(session.connectUrl)`.
- **Development workflow** supports local testing via `pnpm bb dev index.ts`, which exposes `http://127.0.0.1:14113` for `curl` verification.
- **Deployment** with `pnpm bb publish index.ts` generates a Function ID for REST API invocation at `/v1/functions/<FUNCTION_ID>/invoke`.

## Frequently Asked Questions

### What is the difference between Browserbase Functions and running Playwright locally?

Browserbase Functions execute your Playwright code inside Browserbase's managed infrastructure rather than your local machine. While local Playwright runs on your hardware, Browserbase Functions provide auto-scaling, persistent sessions, and remote invocation via REST API, eliminating the need to manage browser binaries or infrastructure.

### How does the `context.session.connectUrl` parameter work?

The `context.session.connectUrl` is a secure Chrome DevTools Protocol (CDP) endpoint provided by Browserbase. When your function executes, Browserbase provisions a fresh Chromium instance and exposes it through this URL. Your handler uses `chromium.connectOverCDP()` to establish a connection, enabling standard Playwright operations on a remote browser as if it were local.

### Can I deploy Browserbase Functions using environment variables other than `.env`?

Yes. While the CLI generates a `.env` template for local development, production deployments can inject `BROWSERBASE_API_KEY` and `BROWSERBASE_PROJECT_ID` through your CI/CD pipeline's secret management system. The SDK reads these variables at runtime, regardless of whether they originate from a `.env` file or the hosting environment's secret store.

### What happens if my function returns a non-JSON-serializable value?

The SDK requires all return values to be JSON-serializable. If your handler returns circular references, BigInt values, or other non-serializable objects, the function will fail at runtime. Always return plain objects, arrays, strings, numbers, or booleans to ensure the invocation payload can be stored and retrieved via the Browserbase API.