Skip to main content
Send a shareable link so someone can demonstrate a task in a live browser. Anchor captures every event and compiles it into deterministic, repeatable code with an AI fallback — the same outcome as creating a task from a demonstration in the UI. Use this when the person who knows the flow isn’t at the keyboard in your Anchor workspace.

How it works

  1. Create a demonstration session via API — you get back a share_url
  2. Send the link to the person who will demonstrate the task
  3. They open it, see a live browser, and perform the task
  4. They click Finish Demonstration — the demonstration is submitted
  5. Anchor compiles the captured events into a task
  6. Poll the status endpoint until it reaches completed — you get task_id and tool_id

API Endpoints

Create a demonstration

import AnchorBrowser from 'anchorbrowser';

const anchorClient = new AnchorBrowser({ apiKey: process.env.ANCHOR_API_KEY });

const demo = await anchorClient.post('/v1/demonstrations/', {
  body: {
    task_name: 'Download invoice report',
    task_description: 'Navigate to Reports, select the monthly invoice report, and download it as PDF',
    user_name: 'John',
  },
});

console.log('Share URL:', demo.share_url);
console.log('Session ID:', demo.session_id);
console.log('Task ID:', demo.task_id);
import os
from anchorbrowser import Anchorbrowser

anchor_client = Anchorbrowser(api_key=os.getenv('ANCHOR_API_KEY'))

demo = anchor_client.post(
    '/v1/demonstrations/',
    body={
        'task_name': 'Download invoice report',
        'task_description': 'Navigate to Reports, select the monthly invoice report, and download it as PDF',
        'user_name': 'John',
    },
)

print('Share URL:', demo['share_url'])
print('Session ID:', demo['session_id'])
print('Task ID:', demo['task_id'])
Request body:
FieldTypeRequiredDescription
task_namestringYesName for the task being demonstrated
task_descriptionstringYesNatural language description of what the task does — helps Anchor interpret the demonstration
identity_idstringNoPre-authenticate the browser with a saved identity
identity_skip_validationbooleanNoSkip identity validation (default: true)
user_namestringNoDisplay name shown in the demonstration UI (“Thanks, John!”)
session_configobjectNoOverride browser session settings (start URL, proxy, timeouts, etc.)
Response:
{
  "session_id": "abc123-...",
  "live_view_url": "https://connect.anchorbrowser.io/...",
  "share_url": "https://app.anchorbrowser.io/demonstrate?token=eyJ...",
  "share_token": "eyJ...",
  "share_expires_at": "2026-04-15T09:00:00.000Z",
  "task_id": "task-uuid-..."
}
The share_url is a signed JWT link valid for 1 hour. The customer does not need an Anchor account — the token contains the session and team context.

Get demonstration status

Poll this endpoint to track progress after the demonstration is submitted.
const status = await anchorClient.get(`/v1/demonstrations/${sessionId}`);
console.log(status);
status = anchor_client.get(f'/v1/demonstrations/{session_id}')
print(status)
Response:
{
  "session_id": "abc123-...",
  "status": "completed",
  "hektor_project_id": "proj-uuid-...",
  "task_id": "task-uuid-...",
  "task_version_id": "ver-uuid-...",
  "tool_id": "tool-uuid-...",
  "created_at": "2026-04-15T07:32:12.865Z"
}
Status values:
StatusDescription
recordingBrowser session is live — demonstration in progress
processingDemonstration complete — Anchor is compiling the task
completedTask generated — task_id and tool_id are available
failedTask generation failed
stoppedSession was stopped before completing

Complete demonstration

Called automatically when the user clicks Finish Demonstration. Can also be called programmatically via POST .../recording/complete.
const result = await anchorClient.post(
  `/v1/demonstrations/${sessionId}/recording/complete`,
);
console.log(result);
result = anchor_client.post(f'/v1/demonstrations/{session_id}/recording/complete')
print(result)
Response:
{
  "session_id": "abc123-...",
  "status": "processing",
  "hektor_project_id": "proj-uuid-...",
  "task_id": "task-uuid-..."
}
This endpoint:
  1. Ends the browser session and uploads the captured events
  2. Waits for demonstration artifacts to be stored
  3. Submits them for task generation
  4. Returns immediately with status: "processing"

Stop demonstration

Stop a demonstration without generating a task. Useful for cleanup.
const result = await anchorClient.post(`/v1/demonstrations/${sessionId}/stop`);
console.log(result);
result = anchor_client.post(f'/v1/demonstrations/{session_id}/stop')
print(result)
Response:
{
  "success": true
}

End-to-end example

import AnchorBrowser from 'anchorbrowser';

const anchorClient = new AnchorBrowser({ apiKey: process.env.ANCHOR_API_KEY });

// 1. Create demonstration
const demo = await anchorClient.post('/v1/demonstrations/', {
  body: {
    task_name: 'Download invoice report',
    task_description: 'Go to Reports > Invoices, select this month, download PDF',
    identity_id: 'your-identity-id',
    user_name: 'Sarah',
  },
});

console.log(`Send this link to your customer: ${demo.share_url}`);
const sessionId = demo.session_id;

// 2. Poll until completed
let status;
while (true) {
  status = await anchorClient.get(`/v1/demonstrations/${sessionId}`);
  console.log(`Status: ${status.status}`);

  if (['completed', 'failed', 'stopped'].includes(status.status)) break;
  await new Promise((r) => setTimeout(r, 5000));
}

// 3. Use the generated task
if (status.status === 'completed') {
  console.log(`Task ID: ${status.task_id}`);
  console.log(`Tool ID: ${status.tool_id}`);
}
import os
import time
from anchorbrowser import Anchorbrowser

anchor_client = Anchorbrowser(api_key=os.getenv('ANCHOR_API_KEY'))

# 1. Create demonstration
demo = anchor_client.post(
    '/v1/demonstrations/',
    body={
        'task_name': 'Download invoice report',
        'task_description': 'Go to Reports > Invoices, select this month, download PDF',
        'identity_id': 'your-identity-id',
        'user_name': 'Sarah',
    },
)

print(f"Send this link to your customer: {demo['share_url']}")
session_id = demo['session_id']

# 2. Poll until completed
while True:
    status = anchor_client.get(f'/v1/demonstrations/{session_id}')
    print(f"Status: {status['status']}")

    if status['status'] in ('completed', 'failed', 'stopped'):
        break

    time.sleep(5)

# 3. Use the generated task
if status['status'] == 'completed':
    print(f"Task ID: {status['task_id']}")
    print(f"Tool ID: {status['tool_id']}")

Identity pre-authentication

Pass an identity_id to pre-authenticate the browser before the link is opened. The user will see the target application already logged in and can start the demonstration immediately.
{
  "task_name": "Export quarterly report",
  "task_description": "Navigate to the reports section and export Q1 data",
  "identity_id": "7f0db4ad-74ca-42e5-896e-3f0daea36c13"
}
If identity authentication fails (expired credentials, site unreachable), the session still starts — the user can log in manually during the demonstration. Set identity_skip_validation: true (default) to ensure this behavior.

Share URL and the demonstration UI

The share_url opens a full-screen demonstration interface with:
  • Live browser — interact with the actual website
  • Live Browser Events panel — clicks, typing, and navigation as they happen
  • Finish Demonstration — submits the demonstration and starts task generation
When the user finishes, they see a confirmation screen. If the share URL was opened as a popup (via window.open), the parent window receives a demonstration-complete postMessage with the task_id, task_version_id, and tool_id.

Session configuration

Override default session settings:
{
  "task_name": "My task",
  "task_description": "Task description",
  "session_config": {
    "browser": {
      "start_url": "https://app.example.com/dashboard"
    },
    "session": {
      "timeout": {
        "max_duration": 60,
        "idle_timeout": 30
      }
    }
  }
}
Default demonstration timeouts are max_duration: 30 minutes and idle_timeout: 30 minutes.