Skip to content

Your first run

This page walks you through your first end-to-end run in detail. If you just want to ship a curl command, see the quickstart.

What a “run” is

A run is one URL × one or more personas. Each persona executes in an isolated browser session inside a Cloudflare Container, driven by a Pi-based agent loop. When a run finishes:

  • Each session emits four artifacts: transcript.json.gz, report.json, report.md, report.html, plus a screenshots/ directory.
  • For multi-persona runs, an aggregate report is synthesized across sessions.

1. Choose a target URL

Anything publicly reachable over HTTPS. We block private IP ranges, .local and .internal TLDs, and any non-https:// scheme (SSRF protection — see architecture).

Terminal window
TARGET="https://staging.example.com/"

If your staging URL is gated behind basic auth or requires a sign-in, provision a credential first.

2. Choose a persona

Terminal window
curl -s "$API_URL/personas" \
-H "Authorization: Bearer $SYNTHUSERS_API_KEY" \
| jq '.items[] | { id, name, role_description }'

Pick one whose voice matches your real user. Library personas are read-only; you can create custom personas too.

3. Optionally specify a task

If you give the agent a task, it tries to complete that task in the persona’s voice. Without a task, it browses freely and reacts to what it sees.

{
"target_url": "https://staging.example.com/",
"persona_ids": ["pers_..."],
"task": "Find pricing, then attempt to start a free trial.",
"duration_budget": "short",
"guided_exploration": "off"
}
duration_budgetWall-clock capTurn cap
short~3 min15 turns
medium~20 min120 turns

Short is the right default. Most useful signal lands in the first 8–10 turns. Use guided_exploration: "standard" or "deep" when you want the run to track explicit evidence-seeking questions in the final report.

4. Submit

Terminal window
RUN=$(curl -s -X POST "$API_URL/runs" \
-H "Authorization: Bearer $SYNTHUSERS_API_KEY" \
-H "Content-Type: application/json" \
-d "{ \"target_url\": \"$TARGET\", \"persona_ids\": [\"pers_...\"] }")
RUN_ID=$(echo "$RUN" | jq -r .run_id)
echo "Run started: $RUN_ID"

5. Poll (or wait for a webhook)

Terminal window
while true; do
STATUS=$(curl -s "$API_URL/runs/$RUN_ID" \
-H "Authorization: Bearer $SYNTHUSERS_API_KEY" \
| jq -r .status)
echo "[$RUN_ID] $STATUS"
[ "$STATUS" = "completed" ] && break
[ "$STATUS" = "failed" ] && break
sleep 5
done

Or register a webhook and let us push the completion event.

6. Pull the report

Terminal window
# Find the first session's id
SID=$(curl -s "$API_URL/runs/$RUN_ID" \
-H "Authorization: Bearer $SYNTHUSERS_API_KEY" \
| jq -r '.sessions[0].id')
# Per-session report — JSON
curl -s "$API_URL/runs/$RUN_ID/sessions/$SID/report.json" \
-H "Authorization: Bearer $SYNTHUSERS_API_KEY"
# ...or Markdown
curl -s "$API_URL/runs/$RUN_ID/sessions/$SID/report.md" \
-H "Authorization: Bearer $SYNTHUSERS_API_KEY"

If you ran more than one persona, fetch the cross-persona summary with GET /runs/$RUN_ID/aggregate-report.json (or .md).

What you’ll see

The Markdown report has these sections by default:

  1. Persona — who they are, what they wanted.
  2. Journey — what they did, step by step.
  3. Confusion points — places they got stuck or asked “what is this?”.
  4. Quotes — verbatim first-person reactions to the experience.
  5. Questions explored — only for guided exploration runs.

See interpreting reports for what to do with each section.