npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@render-lab/tasks-browserbase

v0.1.2

Published

> ⚠️ **Experimental: proof of concept.** This package is part of the [Render Tasks](https://github.com/render-lab/render-tasks) POC and is published for testing only. It is not fully tested or production ready. Task names, inputs, outputs, and behavior ca

Readme

@render-lab/tasks-browserbase

⚠️ Experimental: proof of concept. This package is part of the Render Tasks POC and is published for testing only. It is not fully tested or production ready. Task names, inputs, outputs, and behavior can change or break in any release. Pin exact versions and expect breaking changes.

Durable Browserbase tasks for Render Workflows.

This pack drives Browserbase's managed Chrome sessions from durable workflow tasks. It uses the official @browserbasehq/sdk for the control plane (contexts, sessions, uploads, downloads, logs, replay) and playwright-core for browser automation over CDP.

Reconnect-per-operation. Nothing holds a live browser between tasks. Each browser operation (runActions, captureScreenshot) retrieves the session's debug WebSocket URL, calls chromium.connectOverCDP, drives the first page, and always closes the local CDP connection in finally. Closing that local connection never releases a keepAlive session — so the next task reconnects to the same session — and closeSession is the only thing that sends REQUEST_RELEASE. This keeps every task a short-lived, restartable, observable durable run.

import {
  createContext,
  deleteContext,
  createSession,
  getSession,
  closeSession,
  runActions,
  captureScreenshot,
  uploadFiles,
  listDownloads,
  getDownload,
  getSessionLogs,
  getSessionReplay,
} from "@render-lab/tasks-browserbase";

Tasks

| Task | Input | Output | Retry | | --- | --- | --- | --- | | browserbase.createContext | CreateContextInput | CreateContextResult | none (0 retries) | | browserbase.deleteContext | DeleteContextInput | DeleteContextResult | convergent (3× backoff) | | browserbase.createSession | CreateSessionInput | CreateSessionResult | convergent (3× backoff) | | browserbase.getSession | SessionIdInput | SessionDTO | read (3× backoff) | | browserbase.closeSession | SessionIdInput | CloseSessionResult | convergent (3× backoff) | | browserbase.runActions | RunActionsInput | RunActionsResult | none (0 retries) | | browserbase.captureScreenshot | CaptureScreenshotInput | CaptureScreenshotResult | none (0 retries) | | browserbase.uploadFiles | UploadFilesInput | UploadFilesResult | none (0 retries) | | browserbase.listDownloads | ListDownloadsInput | ListDownloadsResult | read (3× backoff) | | browserbase.getDownload | GetDownloadInput | GetDownloadResult | read (3× backoff) | | browserbase.getSessionLogs | GetSessionLogsInput | GetSessionLogsResult | read (3× backoff) | | browserbase.getSessionReplay | GetSessionReplayInput | GetSessionReplayResult | read (3× backoff) |

Retry classes (from retry.ts; the SDK is built with maxRetries: 0, so the durable task retry is the single source of truth):

  • nonecreateContext, runActions, captureScreenshot, and uploadFiles. A context create has no find-or-create, and browser actions, screenshots, and uploads are side effects; a silent replay after an ambiguous failure could leak a paid context, re-run a click, or double-upload. Every attempt is one observable run.
  • convergentcreateSession (find-or-create by reserved metadata), closeSession (reads first, releases an active session once), and deleteContext (a repeated/404 delete normalizes to deleted: false). A retry settles on the same terminal state instead of duplicating work.
  • readgetSession, listDownloads, getDownload, getSessionLogs, and getSessionReplay. Safe to repeat, so transient network/rate-limit/5xx failures retry with backoff over ~1s, 2s, 4s.

Idempotent sessions

createSession requires a caller idempotencyKey. The key is stored in the reserved _render_tasks_idempotency_key user-metadata field (the port overwrites any caller attempt to set it). Before creating, the task queries for an existing session with that key and returns it with created: falseeven if it is COMPLETED, ERROR, or TIMED_OUT — so a retried create never starts a second paid session. A fresh key returns created: true.

const ctx = await createContext({});

const session = await createSession({
  idempotencyKey: `crawl:${jobId}`,
  contextId: ctx.contextId,
  keepAlive: true, // let each task reconnect to the same session
});

await runActions({
  sessionId: session.sessionId,
  actions: [
    { type: "goto", url: "https://example.com" },
    { type: "fill", selector: "#q", value: "render workflows" },
    { type: "press", key: "Enter" },
    { type: "waitForSelector", selector: ".results", state: "visible" },
    { type: "extractText", selector: ".results", maxBytes: 262_144 },
  ],
});

const shot = await captureScreenshot({
  sessionId: session.sessionId,
  fullPage: true,
  maxBytes: 524_288,
});

// Session and context IDs are the only handles that cross task boundaries.
await closeSession({ sessionId: session.sessionId }); // sends REQUEST_RELEASE
await deleteContext({ contextId: ctx.contextId });

Session and context IDs are the only handles that cross a task boundary. No connectUrl, debug URL, Playwright object, Buffer, stream, or Date is ever returned — only JSON-serializable DTOs (ADR-0003).

Browser actions

runActions accepts 1 to 50 actions and runs them in order against the first page, returning the resulting URL and title after each so partial progress is diagnosable. Supported action types: goto, click, fill, press, select, waitForSelector, and extractText (bounded to maxBytes, default 256 KiB). The action switch is exhaustive with a compile-time never check — an unknown action type is a type error, not a permissive default. actionTimeoutMs defaults to 30,000 and caps at 120,000. Actions get zero retries: an ambiguous connection failure never silently replays a side-effecting action.

Payload limits and the 4 MB cap

Every artifact-bearing task returns a bounded shape from @render-lab/tasks-core (ADR-0020) so a task result can never exceed the Render Workflows 4 MB argument/result cap. Binary is all-or-nothing (a partial screenshot or download is misleading) and rejects before returning; text truncates on a UTF-8 boundary and reports the original byte count.

| Task | Field | Default | Maximum | | --- | --- | --- | --- | | runActions (extractText) | maxBytes | 262,144 | 1,048,576 | | captureScreenshot | maxBytes | 524,288 | 2,097,152 | | uploadFiles | maxTotalBytes (decoded, aggregate) | 1,048,576 | 2,097,152 | | getDownload | maxBytes | 1,048,576 | 2,097,152 | | listDownloads | limit | 20 | 100 | | getSessionLogs | limit / maxBytes (aggregate) | 100 / 262,144 | 500 / 1,048,576 | | getSessionReplay | limit | 20 | 100 |

getDownload reads download metadata first and rejects an oversized file before fetching its bytes. getSessionLogs serializes each log's request/response to JSON, bounds them independently, and stops adding records once the aggregate returned bytes reach maxBytes. getSessionReplay returns page metadata and signed playlist URLs only — never HLS manifests or media segments. When a payload is too large, narrow the request, lower the limit, or retrieve the artifact from the Browserbase-managed download/replay URL directly.

No webhooks

This wave ships no webhook adapter. Browserbase session state is observed by polling getSession and released with an explicit closeSession; there is no general session-completion webhook subpath.

Install

pnpm add @render-lab/tasks-browserbase @renderinc/sdk

@renderinc/sdk is a peer dependency, pinned to an exact version. @browserbasehq/sdk and playwright-core are regular dependencies encapsulated inside the tasks; playwright-core does not download a browser — it only connects to Browserbase over CDP.

Environment contract

| Variable | Required | Purpose | | --- | --- | --- | | BROWSERBASE_API_KEY | for all browserbase.* tasks | Browserbase API key. Read lazily at the first API call, never at import; the SDK client is constructed once, on first use, with maxRetries: 0. | | BROWSERBASE_PROJECT_ID | optional | Default project for createContext / createSession when the operation does not name one and the key cannot infer it. Read lazily. |

Credentials are read lazily at first use. Constructing the port (or importing the pack) never reads them, so importing this pack for one task never requires another's secret.

Testing

pnpm -C packages/tasks-browserbase build
pnpm -C packages/tasks-browserbase test        # hermetic Tier 1 (no secrets, no network)
pnpm -C packages/tasks-browserbase typecheck
RUN_LIVE=1 BROWSERBASE_API_KEY=bb_... pnpm -C packages/tasks-browserbase test:live  # opt-in Tier 2

The raw *Impl functions take an injected BrowserbaseDeps, so they unit-test against a fake BrowserbasePort with no network. The port itself is tested against structural SDK/CDP fakes in test/client.test.ts.