Automation

Recording

Recording turns a live browser session into a replayable TypeScript script and supports both local and cloud sessions.

Recording

opensteer record captures a live browser flow and writes a replayable TypeScript script.

Important requirements

  • record requires a workspace.
  • record requires the Playwright engine.
  • Local recording requires a headed browser.
  • record does not support attach mode.

Local recording

Start a local recording:

opensteer record https://example.com --workspace demo

You can also pass the URL with --url:

opensteer record --workspace demo --url https://example.com

OpenSteer launches the browser, installs the recorder, and waits until you click the in-browser stop control.

Cloud recording

Cloud recording uses the managed browser session UI instead of a local browser window.

Required environment:

export OPENSTEER_PROVIDER=cloud
export OPENSTEER_API_KEY=your_api_key
export OPENSTEER_BASE_URL=https://your-control-api
export OPENSTEER_CLOUD_APP_BASE_URL=https://your-cloud-app

Then run:

opensteer record https://example.com --workspace demo --provider cloud

Output path

By default the script is written to:

.opensteer/workspaces/<workspace>/recorded-flow.ts

Override it with --output <path>.

What the generated script preserves

The recorder is not just a raw event dump. The generated script preserves the useful browser flow:

  • multi-tab flows
  • navigation steps
  • switch-tab and close-tab events
  • consolidated text input
  • scroll distances
  • cloud bootstrap when the recording came from cloud mode

Example output

import { Opensteer } from "opensteer";

const opensteer = new Opensteer({
  workspace: "demo",
  rootDir: process.cwd(),
});

const page0 = (await opensteer.open("https://example.com")).pageRef;
await opensteer.input({ selector: "#search", text: "laptop" });
await opensteer.click({ selector: "button[type='submit']" });
await opensteer.close();

Good flow

Recording is best for the first draft of a browser flow. After that:

  1. replace brittle selectors where needed
  2. simplify the generated code
  3. move final request logic into fetch() when the browser is no longer necessary