Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.nusomi.com/llms.txt

Use this file to discover all available pages before exploring further.

The SDK capture path is for runs without a human at the keyboard — Playwright suites, scripted automations, agent runs in CI, Browserbase / Anchor sessions. It produces sessions with the same shape as desktop or browser capture, so they’re indistinguishable downstream.

Install

# TypeScript
npm install @nusomi/sdk

# Python
pip install nusomi

Wrapping a Playwright page

import { chromium } from "playwright";
import { Nusomi } from "@nusomi/sdk";

const nusomi = new Nusomi({ apiKey: process.env.NUSOMI_API_KEY });
const session = await nusomi.sessions.create({
  workflow: "scraper_login",
});

const browser = await chromium.launch();
const context = await browser.newContext();

// Attach Nusomi to the Playwright context
await session.attachPlaywright(context);

await session.start();

const page = await context.newPage();
await page.goto("https://app.example.com/login");
await page.fill("[name=email]", "ops@acme.com");
await page.fill("[name=password]", process.env.PASSWORD!);
await page.click("button[type=submit]");

await session.stop();
await browser.close();
attachPlaywright instruments the context to emit Nusomi events automatically — no need to call session.event(...) for every action. You still get a real frame stream because the SDK takes screenshots at the configured rate.

Wrapping Puppeteer

import puppeteer from "puppeteer";
import { Nusomi } from "@nusomi/sdk";

const browser = await puppeteer.launch();
const page = await browser.newPage();

const session = await nusomi.sessions.create({ workflow: "..." });
await session.attachPuppeteer(page);
await session.start();
// ...
await session.stop();

Browserbase / Anchor / Steel

These platforms run remote browsers but expose a CDP endpoint. Connect Nusomi via CDP:
const session = await nusomi.sessions.create({ workflow: "..." });
await session.attachCdp({ wsEndpoint: browserbaseSession.connectUrl });
await session.start();
// ...
await session.stop();

Manual events

You don’t have to attach to a browser at all. Push events directly:
const session = await nusomi.sessions.create({ workflow: "queue_processor" });
await session.start();

await session.event("click", {
  target: { role: "button", name: "Approve" },
  x: 612,
  y: 388,
});

await session.event("submit", {
  form: "approval_form",
  payload: { approved: true },
});

await session.stop();

Frame uploads

If your run produces its own frames (server-rendered preview, headless pixel capture), upload them directly:
await session.frame({
  t_ms: 12_480,
  image: fs.readFileSync("frame_1.webp"),
  viewport: { w: 1440, h: 900 },
});

Buffering & retries

The SDK buffers frames and events locally and retries on transient network failures. By default:
  • Frame upload: 5 retries with exponential backoff, 60s total budget.
  • Event upload: 5 retries, 30s budget.
  • Buffer size: 200 MB on disk before back-pressuring.
Override:
new Nusomi({
  apiKey: ...,
  buffer: { maxBytes: 1_000_000_000, dir: "/var/cache/nusomi" },
  retries: { events: 10, frames: 10 },
});

Sealing in CI

Always wrap a session in try / finally so a thrown test error doesn’t leave it recording forever:
const session = await nusomi.sessions.create({ workflow: "smoke_test" });
try {
  await session.start();
  await runSuite();
} finally {
  await session.stop();
}

Self-hosted endpoint

new Nusomi({
  apiKey: process.env.NUSOMI_API_KEY,
  baseUrl: "https://nusomi.internal.acme.com",
});