CAPABILITY · OBSERVABILITY

Watch the session while it runs, keep the recording after

POST /api/v1/live streams the browser back as Server-Sent Events while the agent works, and an opted-in run keeps a durable video you can fetch long afterwards.

POST /api/v1/live · GET /api/v1/runs/{id}/video

Capability

Inside live view & session video

Headless automation is a black box until it breaks. The live endpoint takes the same body as a run and answers with a Server-Sent Events stream instead of a result: a meta frame carrying the runId, then JPEG frames as the browser paints, then a terminal result frame. Recording is opt-in per run and tiered by plan, and a recorded run is replayable from durable storage after the fact.

A real stream, not a poll

The response is text/event-stream: `event: meta` with the runId, then `event: frame` JPEG frames, then `event: result`. No polling loop and no second connection.

Recording is opt-in and tiered

Pass record: true on a run to keep a video. It is opt-in because storage is not free, and the size ceiling is tiered by plan — a recorded run is also annotated by default so the video shows the cursor travel.

The recording ends on the end state

A recorded run holds a video tail so the last frame is the run's RESULT page rather than the moment before the final click, and the file is only published once it has stopped growing.

Fetched from durable storage

GET /api/v1/runs/{id}/video serves the bytes from storage, lazily persisted from the engine on first view. A run that was not recorded answers 404 rather than pretending.

How it works

The mechanism, in execution order

4 stages, in the order the runtime performs them — not a summary of them.

LIVE VIEW · RECORDINGliveSign intake overmid-runrecordingsession videoaligned to the stepswatch it happen · step in without restarting · replay it later
  1. 1Start with a streamPOST /api/v1/live with the same body as /run. The response is an SSE stream, and the meta frame gives you the runId immediately.
  2. 2Watch it paintFrame events carry JPEG snapshots of the session as it executes. A live run can also be interacted with mid-flight.
  3. 3Settle on the terminal frameThe result event ends the stream. Billing settles once on that frame or on disconnect — a failed run with no result is refunded in full.
  4. 4Replay laterA run created with record: true keeps a video. GET /api/v1/runs/{id}/video streams it back.

In practice

A call you can paste and run

One request, one stream: meta, frames, result. The recording is a separate fetch once the run is over.

live.shbash
# Stream the browser while it works
curl -N https://twin-browser.com/api/v1/live \
  -H "Authorization: Bearer $TWIN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"url":"https://app.example.com/reports",
       "prompt":"open the Q2 report and export it as CSV",
       "success":{"kind":"textVisible","value":"Export complete"},
       "record":true}'

# event: meta
# data: {"runId":"run_…"}
# event: frame
# data: {"jpeg":"…base64…"}
# event: result
# data: {"success":true,"steps":6}

# Afterwards — the durable recording
curl "https://twin-browser.com/api/v1/runs/run_…/video" -H "Authorization: Bearer $TWIN_API_KEY" -o run.webm
api.twin-browser.com
  1. Start with a streamdone
  2. Watch it paintrunning
  3. Settle on the terminal framequeued
  4. Replay laterqueued

What it costs, how to switch it on

Priced from the same rate card the API serves

Every credit figure on this page is read from the rate card behind GET /api/v1/pricing — it is not typed into the copy, so it cannot drift from what you are billed.

10-credit floor per streamed run

A live run is metered exactly like POST /run: higher-of(10-credit floor, metered model + compute + egress), settled once on the terminal frame or on disconnect. A run that failed or produced no result is refunded in full. Fetching a recording afterwards is not a separate charge; the storage ceiling is what your plan tiers.

Full rate card

Turning it on

  1. 1Swap the endpointPOST /api/v1/live takes the same body as POST /api/v1/run. Nothing else changes.
  2. 2Opt into recordingAdd record: true to any run, job or live call. It is off by default because storage is metered against your plan.
  3. 3Keep the runIdThe meta frame carries it. It is how you fetch the video, read the run, or drive it if it parks.
  4. 4Or record without watchingrecord_run and record_job over MCP submit a run that captures video without holding a stream open.

At a glance

The contract, in the fewest rows that say it

PropertyTwin Browser
StreamPOST /api/v1/live (text/event-stream)
Framesmeta → frame* → result
Recording`record: true` on the run body
PlaybackGET /api/v1/runs/{id}/video
AnnotationOn by default for a recorded run
SettlementOnce, on the terminal frame or disconnect

Limits

Where it stops, and what it deliberately does not do

A capabilities page with no limits section is a brochure. These are the ceilings, the defaults that will surprise you, and the things this capability is not.

Limits and defaults

  • Recording is opt-in per call, and the video size ceiling is tiered by plan.
  • GET /runs/{id}/video answers 404 when the run was not recorded or the recording is no longer available — a missing video is not an error state to retry.
  • The stream settles billing once. A client that disconnects early still settles; it does not get a free run.
  • Live frames are JPEG snapshots of the session, not a lossless capture — the durable recording is the artefact for review.

What it does not do

  • It does not record every run silently. Nothing is captured unless you asked for it.
  • It does not keep recordings without bound. Storage is capped per plan, and an old recording can be gone.
  • It does not stream a run started elsewhere. To watch an already-parked run, use GET /runs/{id}/stream instead.
  • It does not expose the video as a public URL. Playback is authenticated on your key like every other endpoint.

FAQ

Questions about live view & session video

Can I watch a run while it happens?
Yes — POST /api/v1/live returns a Server-Sent Events stream of the browser: a meta frame with the runId, JPEG frames as it paints, then a terminal result frame.
Is every run recorded?
No. Recording is opt-in per call with record: true, and the size ceiling is tiered by plan. That is deliberate — storage is a real cost and most runs never need to be watched again.
Why does the recording show the result page and not the last click?
Because a recorded run holds a video tail after the final action, so the recording ends on the run's end state rather than the frame before it, and the file is only published once it has stopped growing.
How do I watch a run that has already paused?
GET /api/v1/runs/{id}/stream mirrors the parked browser as SSE. It drives no agent and costs no credits — pair it with POST /runs/{id}/input to take the wheel.

Put your agent to work. Keep the decision.

Start free. Hand your agent a goal on a site you authorize, set the guardrails, and let the first successful run compile the skill every run after it replays.