Agent skill

Browserbase Webhooks Skill

Receive and verify Browserbase webhooks (headless browser platform). Use when setting up a Browserbase webhook endpoint, storing the whsec_ signing secret (shown only on create or rotate), debugging Standard Webhooks signature verification (webhook-id, webhook-timestamp, webhook-signature), rotating secrets, or handling Browserbase Functions events like functions.invocations.completed, functions.invocations.failed, functions.builds.completed and functions.builds.failed.

Install this skill

npx skills add hookdeck/webhook-skills --skill browserbase-webhooks


Browserbase is a headless browser platform. Its webhooks POST a signed event to your HTTPS endpoint when a Browserbase Function invocation or build changes state, so you don't have to poll GET /v1/functions/invocations/{id}. Deliveries follow the Standard Webhooks spec.

When to Use This Skill

  • How do I receive Browserbase webhooks?
  • How do I verify a Browserbase webhook signature?
  • Where do I find my Browserbase webhook signing secret? (Only in the create or rotate response.)
  • How do I handle functions.invocations.completed and functions.invocations.failed?
  • Why is my Browserbase webhook-signature verification failing?
  • How do I rotate a Browserbase webhook secret without dropping deliveries?

Verification (core)

HeaderValue
webhook-idUnique message identifier
webhook-timestampUnix seconds when the delivery was sent
webhook-signaturev1,<base64 HMAC-SHA256>, possibly several space-separated entries

Signed content is {webhook-id}.{webhook-timestamp}.{raw body}. The HMAC key is the base64-decoded part of the whsec_ secret. Browserbase's docs say to use a Standard Webhooks library (standardwebhooks on npm and PyPI) instead of hand-rolling the HMAC. It handles the constant-time comparison and a 5-minute timestamp tolerance.

const { Webhook } = require('standardwebhooks');

// Current secret first; after a rotation the old one keeps verifying for 24h.
const secrets = [process.env.BROWSERBASE_WEBHOOK_SECRET, process.env.BROWSERBASE_WEBHOOK_SECRET_PREVIOUS].filter(Boolean);
if (secrets.length === 0) throw new Error('BROWSERBASE_WEBHOOK_SECRET not set'); // fail closed → 500

function verifyBrowserbaseWebhook(rawBody, headers) { // rawBody: exact bytes, NOT re-serialised JSON
  let lastError;
  for (const secret of secrets) {
    try {
      return new Webhook(secret).verify(rawBody, headers); // strips whsec_, base64-decodes key
    } catch (err) { lastError = err; }
  }
  throw lastError;                                      // → 400 Invalid signature
}

Python: from standardwebhooks.webhooks import Webhook, then Webhook(secret).verify(await request.body(), headers).

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Event Envelope

{
  "id": "85e6ff2d-91de-468a-867c-e0d9e4587063",
  "type": "functions.invocations.completed",
  "resourceId": "a3f1c2d4-7b90-4e51-9c8a-2f6d1e0b4c73",
  "data": { }
}

id identifies the event and stays the same across retries, so use it as your deduplication key. type is the event type, resourceId is the invocation or build the event concerns, and data holds type-specific fields. Browserbase may add envelope keys but won't rename or remove them, so ignore keys you don't recognize.

Common Event Types

EventFires when
functions.invocations.pendingBrowserbase accepts and queues an invocation
functions.invocations.runningAn invocation starts executing
functions.invocations.completedAn invocation finishes successfully
functions.invocations.failedAn invocation fails
functions.builds.runningA build (publish of your Function code) starts
functions.builds.completedA build finishes successfully
functions.builds.failedA build fails

An endpoint receives only the types it subscribes to. Browserbase rejects a subscription to an unknown type when you register the endpoint. See references/overview.md.

Delivery Semantics

  • Return any 2xx within 15 seconds. The response body is ignored. A 3xx redirect counts as a failure, so register the final URL.
  • Retries run immediately, then after 5s, 5m, 30m, 2h, 5h, 10h and 10h (eight attempts in total). An endpoint that fails continuously for five days is disabled.
  • The same event can arrive more than once. Dedupe on the envelope id.
  • Events aren't ordered: a completed event can arrive before running for the same invocation. Branch on type, not arrival order.

Environment Variables

BROWSERBASE_WEBHOOK_SECRET=whsec_...            # required; handlers fail closed without it
BROWSERBASE_WEBHOOK_SECRET_PREVIOUS=            # optional, during the 24h rotation window

Local Development

# Express / Next.js (use 8000 for FastAPI). No install or account required.
npx hookdeck-cli listen 3000 browserbase --path /webhooks/browserbase

Register the printed https:// URL as the webhook endpoint (Browserbase rejects http://), then invoke a Function to trigger an event.

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Oct 28, 2026

View on GitHub →