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 ascreenshots/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).
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
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_budget | Wall-clock cap | Turn cap |
|---|---|---|
short | ~3 min | 15 turns |
medium | ~20 min | 120 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
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)
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 5doneOr register a webhook and let us push the completion event.
6. Pull the report
# Find the first session's idSID=$(curl -s "$API_URL/runs/$RUN_ID" \ -H "Authorization: Bearer $SYNTHUSERS_API_KEY" \ | jq -r '.sessions[0].id')
# Per-session report — JSONcurl -s "$API_URL/runs/$RUN_ID/sessions/$SID/report.json" \ -H "Authorization: Bearer $SYNTHUSERS_API_KEY"
# ...or Markdowncurl -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:
- Persona — who they are, what they wanted.
- Journey — what they did, step by step.
- Confusion points — places they got stuck or asked “what is this?”.
- Quotes — verbatim first-person reactions to the experience.
- Questions explored — only for guided exploration runs.
See interpreting reports for what to do with each section.