> ## Documentation Index
> Fetch the complete documentation index at: https://docs.browserbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Build, test, publish, and invoke a Browserbase Function from a local TypeScript project.

This tutorial deploys a Playwright script as a Function, then invokes it through the Browserbase API.

<Warning>
  Functions are currently only available in the **us-west-2** region.
</Warning>

## Prerequisites

You need:

* A Browserbase account
* A Browserbase API key from [Settings](https://www.browserbase.com/settings)
* Node.js and pnpm

## Create a Functions project

<Steps>
  <Step title="Initialize the project">
    Run the Functions initializer:

    ```bash theme={null}
    pnpm dlx @browserbasehq/sdk-functions init my-functions-project
    cd my-functions-project
    ```

    The initializer creates `package.json`, `tsconfig.json`, `.env`, and a starter `index.ts`.
  </Step>

  <Step title="Add your Browserbase API key">
    Add your API key to `.env`:

    ```bash theme={null}
    BROWSERBASE_API_KEY=your_api_key
    ```

    Browserbase resolves the project from the API key. You don't need a Project ID.
  </Step>

  <Step title="Define the Function">
    Replace `index.ts` with a Function that returns the title of a page:

    ```typescript Node.js theme={null}
    import { defineFn } from "@browserbasehq/sdk-functions";
    import { chromium } from "playwright-core";
    import { z } from "zod";

    defineFn(
      "page-title",
      async (context, params) => {
        const browser = await chromium.connectOverCDP(
          context.session.connectUrl,
        );
        const page = browser.contexts()[0]!.pages()[0]!;

        await page.goto(params.url);

        return { title: await page.title() };
      },
      {
        parametersSchema: z.object({
          url: z.string().url(),
        }),
      },
    );
    ```
  </Step>
</Steps>

<Warning>
  Functions don't support pnpm workspaces. Keep `pnpm-lock.yaml` or `package-lock.json` in the Function project directory, not only at a workspace root.
</Warning>

## Test the Function locally

<Steps>
  <Step title="Start the development server">
    Run:

    ```bash theme={null}
    pnpm bb dev index.ts
    ```

    The server listens on `http://127.0.0.1:14113` and reloads when you change the Function files.
  </Step>

  <Step title="Invoke the local Function">
    In another terminal, invoke the Function by the name passed to `defineFn`:

    ```bash theme={null}
    curl --request POST \
      --url http://127.0.0.1:14113/v1/functions/page-title/invoke \
      --header 'Content-Type: application/json' \
      --data '{"params":{"url":"https://example.com"}}'
    ```

    The local server runs the handler synchronously. The response contains:

    ```json theme={null}
    {
      "title": "Example Domain"
    }
    ```
  </Step>
</Steps>

## Publish the Function

Publish the entrypoint:

```bash theme={null}
pnpm bb publish index.ts
```

The command builds each Function reachable from `index.ts` and prints the Function IDs. Save the ID for `page-title`. See [Deploy Functions](/platform/functions/deploy#deploy-from-the-cli) for multi-file projects.

## Invoke the deployed Function

Production invocations run asynchronously. Start an invocation with the Function ID:

```bash theme={null}
curl --request POST \
  --url https://api.browserbase.com/v1/functions/FUNCTION_ID/invoke \
  --header 'Content-Type: application/json' \
  --header "x-bb-api-key: $BROWSERBASE_API_KEY" \
  --data '{"params":{"url":"https://example.com"}}'
```

The API returns `202 Accepted` with an invocation object. Copy its `id`, then poll the invocation:

```bash theme={null}
curl --request GET \
  --url https://api.browserbase.com/v1/functions/invocations/INVOCATION_ID \
  --header "x-bb-api-key: $BROWSERBASE_API_KEY"
```

When `status` is `COMPLETED`, `results` contains the value returned by the handler.

## Next steps

<CardGroup cols={2}>
  <Card title="Write a Function" icon="code" href="/platform/functions/write">
    Configure parameters, browser sessions, and multiple Functions.
  </Card>

  <Card title="Deploy Functions" icon="cloud-arrow-up" href="/platform/functions/deploy">
    Publish from the CLI or the Playground.
  </Card>

  <Card title="Invoke a Function" icon="terminal" href="/platform/functions/invoke">
    Override session settings and handle asynchronous results.
  </Card>
</CardGroup>
