Skip to main content
The Execute API provides a one-shot execution model for ephemeral sessions: start a session, run a script function, return the result, and clean up — all in one call. Use bctrl.execute() for quick automations without manual session management, or point it at an already running named browser with browser. The same primitive is also exposed over HTTP via POST /v1/sessions/{id}/automation with call='execute'. Combine with defineScript() for typed, reusable scripts with Zod parameter validation.

Access

import { Bctrl } from '@bctrl/sdk';

const bctrl = new Bctrl({ apiKey: process.env.BCTRL_API_KEY! });

// One-shot execution
const result = await bctrl.execute({
  fn: async ({ page }) => {
    await page.goto('https://example.com');
    return page.title();
  },
});

Quick Example

import { Bctrl } from '@bctrl/sdk';

const bctrl = new Bctrl({ apiKey: process.env.BCTRL_API_KEY! });

// Simple one-shot execution
const result = await bctrl.execute({
  fn: async ({ page }) => {
    await page.goto('https://example.com');
    return page.title();
  },
});
console.log(result.data); // 'Example Domain'

// Driver-specific execution
const pwResult = await bctrl.execute.playwright({
  fn: async ({ page }) => {
    await page.goto('https://example.com');
    return page.locator('h1').textContent();
  },
});

Methods

One-Shot Execution

Execute a script in a single call. Ephemeral runs are created and cleaned up automatically. Named-browser runs attach to an already running profile and leave it running.

bctrl.execute()

Execute a script function in a managed session. When browser is omitted, bctrl starts an ephemeral session, connects a driver, runs the function, and stops the session afterward. When browser is provided, bctrl attaches to the already running named browser and leaves it running.
options
ExecuteOptions
required
Execution options.
result
ExecuteResult<T>
Execution result.
const result = await bctrl.execute({
  fn: async ({ page }) => {
    await page.goto('https://example.com');
    return page.title();
  },
  timeoutMs: 30_000,
});
console.log(result.data);

bctrl.execute.playwright()

Execute with the Playwright driver. The page parameter is typed as a Playwright page.
options
ExecuteOptionsWithoutDriver
required
Same as execute() options but without driver (pre-set to Playwright).
result
ExecuteResult<T>
Execution result.
const result = await bctrl.execute.playwright({
  fn: async ({ page }) => {
    await page.goto('https://example.com');
    return page.locator('h1').textContent();
  },
});

bctrl.execute.puppeteer()

Execute with the Puppeteer driver. The page parameter is typed as a Puppeteer page.
options
ExecuteOptionsWithoutDriver
required
Same as execute() options but without driver (pre-set to Puppeteer).
result
ExecuteResult<T>
Execution result.
const result = await bctrl.execute.puppeteer({
  fn: async ({ page }) => {
    await page.goto('https://example.com');
    return page.$eval('h1', el => el.textContent);
  },
});

bctrl.execute.stagehand()

Execute with the Stagehand driver. Includes AI capabilities in the page object.
options
ExecuteOptionsWithoutDriver
required
Same as execute() options but without driver (pre-set to Stagehand).
result
ExecuteResult<T>
Execution result.
const result = await bctrl.execute.stagehand({
  fn: async ({ page }) => {
    await page.goto('https://example.com');
    return page.extract('main heading text');
  },
});

bctrl.execute.selenium()

Execute with the Selenium driver.
options
ExecuteOptionsWithoutDriver
required
Same as execute() options but without driver (pre-set to Selenium).
result
ExecuteResult<T>
Execution result.
const result = await bctrl.execute.selenium({
  fn: async ({ page }) => {
    await page.goto('https://example.com');
    return page.title();
  },
});

Script Definitions

Define typed, reusable scripts with Zod parameter validation for execute().

bctrl.defineScript()

Define a reusable, typed script with Zod parameter validation. The returned ScriptDefinition can be passed to execute() for type-safe execution.
input
DefineScriptInput
required
Script definition.
result
ScriptDefinition<TParams, TResult>
A reusable script definition that can be passed to execute().
import { Bctrl } from '@bctrl/sdk';
import { z } from 'zod';

const bctrl = new Bctrl({ apiKey: process.env.BCTRL_API_KEY! });

// Define a reusable script
const scrapeProducts = bctrl.defineScript({
  params: z.object({
    url: z.string().url(),
    maxItems: z.number().default(10),
  }),
  run: async ({ page, url, maxItems }) => {
    await page.goto(url);
    // ... scrape logic
    return products.slice(0, maxItems);
  },
});

// Execute with type-safe params
const result = await bctrl.execute({
  fn: scrapeProducts,
  params: { url: 'https://shop.example.com', maxItems: 5 },
});