Reading results
What each webagent tool returns, what the stop reasons mean, and how long evidence links last.
Your agent gets back a test report, a task result or a skill run. It tells you what it saw. This page helps you check it.
| Tools | Result | Use for |
|---|---|---|
smoke_test, get_report | A test report: one verdict, the steps, console errors and failed network calls | A pass/fail check of a page or flow |
run_task, get_task | A task: a goal the browser agent worked through | Exploring, or a flow you want the agent to judge |
skill_<name>, run_skill, get_skill_run | A skill run: the raw record of a saved check | Reading a skill's own result |
| Any tool, on failure | An error: [code] message | A call that did not run |
get_report also reads the report of a task or a skill run, so every result can be turned into a test report.
The test report
smoke_test and get_report answer with a short text and the whole report as structuredContent. The same report is at GET /v1/skill-runs/:id/report.json and GET /v1/tasks/:id/report.json. It looks the same for a skill run and for a task.
This is the whole report of a real smoke test of a Test Arena address that does not exist, with only the ids and links replaced. The page answered 404, so the second step failed and the network call is listed:
{
"id": "run_us_xxxxxxxxxxxxxxxxxxxxxxxx",
"kind": "skill_run",
"sessionId": "sess_us_xxxxxxxxxxxxxxxxxxxxxxxx",
"name": "smoke-uat@1.2.1",
"verdict": "fail",
"outcome": "failed",
"summary": "Smoke test of https://webagent-test-web.pages.dev/missing-page FAILED in 1 s: 1 of 2 steps passed. Step 2 \"assert 2 conditions\" failed: Page responded without an error status. 1 failed network call (GET /missing-page 404).",
"url": "https://webagent-test-web.pages.dev/missing-page",
"finalUrl": "https://webagent-test-web.pages.dev/missing-page",
"startedAt": "2026-11-12T00:10:56.386Z",
"endedAt": "2026-11-12T00:10:57.319Z",
"durationMs": 933,
"counts": { "steps": 2, "failedSteps": 1, "findings": 0, "consoleErrors": 0, "networkFailures": 1 },
"steps": [
{ "index": 0, "title": "navigate https://webagent-test-web.pages.dev/missing-page", "kind": "navigate", "status": "pass", "ms": 423 },
{
"index": 1,
"title": "assert 2 conditions",
"kind": "assert",
"status": "fail",
"error": "Page responded without an error status",
"ms": 4,
"screenshotUrl": "https://..."
}
],
"findings": [],
"consoleErrors": [],
"networkFailures": [
{ "kind": "http_error", "method": "GET", "url": "https://webagent-test-web.pages.dev/missing-page", "status": 404 }
],
"evidence": {
"reportPath": "/v1/skill-runs/run_us_xxxxxxxxxxxxxxxxxxxxxxxx/report",
"reportSignedUrl": "https://...",
"recordingPath": "/v1/sessions/sess_us_xxxxxxxxxxxxxxxxxxxxxxxx/recording",
"logsPath": "/v1/sessions/sess_us_xxxxxxxxxxxxxxxxxxxxxxxx/logs",
"urlsExpireAt": "2026-11-12T00:15:58.494Z"
},
"notes": []
}A test with steps and an expectText lists every step: the page checks (navigate, check basic-a11y, check broken-links), one act step for each of your steps, check console-errors, then the expectation checks. A check you did not ask for (for example expectUrl when you set only expectText) is listed with status: "skipped". A real report lists up to 50 steps.
The verdict
verdict | Meaning | What to do |
|---|---|---|
pass | The test ran and every check passed. For a task: the agent says it is done. | Nothing. For a task, see the note below |
fail | The test ran and found a problem in the page or the flow. Read summary and the failed steps. | Fix the app, or the test |
error | The test could not run to a result: the run was cancelled, denied a permission, or the browser failed. For a task: the agent could not test (CAPTCHA, a blocked address, an internal error). | This is not a bug in your app. Fix the cause and run again |
running | Not finished. The summary says to call get_report with the id. | Call get_report again |
outcome is the raw result under the verdict: the skill status (passed, failed, error, cancelled, denied) or the task stoppedBy (done, stuck, budget and so on). isError on the tool call is true only for verdict error.
A task pass is not a check
A task has no assertions. For a task report, pass only means the agent says it is done, and the report says so in notes. To check that a text, an address or a result is really there, use smoke_test with expectText, expectUrl or expectNoText.
The fields
| Field | Meaning |
|---|---|
id, kind | The run id (run_…, kind skill_run) or the task id (tsk_…, kind task) |
sessionId | The browser session the test ran in |
name | smoke-uat@1.2.1 for a skill run. The goal, cut to 300 characters, for a task |
summary | Plain sentences you can pass on as they are: what was tested, how many steps passed, the first failed step with its reason, the findings and the console and network totals |
url | The page under test. For a task it is the first page the browser opened, taken from the session log |
finalUrl | Where the browser ended. From the session log, so it is missing until the log is saved |
startedAt, endedAt, durationMs | When it started and ended, and how long it took. endedAt and durationMs appear when it has ended |
counts | The real totals before the lists below are cut: steps, failedSteps, findings, consoleErrors, networkFailures |
steps | Up to 50 steps in order. Each has index (from 0), title, kind, status (pass, fail or skipped), error, ms and, for a failed step of a skill run, a screenshotUrl. When there are more than 50, failed steps come first and a note says how many are shown |
findings | Up to 30 problems the checks found (a broken link, an accessibility issue), worst first. Each has severity (info, low, medium, high, critical), title, and often rule, url, fix and detail. A task has none |
consoleErrors | Up to 15 browser console errors and uncaught page errors: source (console or pageerror), text and url |
networkFailures | Up to 20 failed requests: kind (http_error for a 4xx or 5xx answer, request_failed when nothing came back), method, url, status or error |
evidence | Links to the proof. See below |
notes | Up to 8 sentences on what is missing and why. Read them when a list looks too empty |
A task step has only the action and its target (for example click e12). It has no page address, screenshot or readable label. A report of a skill run has all of these for its steps.
If counts.consoleErrors is larger than the list, only the first entries are shown. Use logsPath for the full log.
Console and network errors come from the session log
Console errors and failed network calls are read from the session log. The log is saved when the session ends. A report read while the session is still open has empty lists, no finalUrl, and this note: "The session log is not available (it is stored when the session ends), so console errors, failed network calls and URLs are missing." That does not mean the page had no errors. Read the report again after the session has ended. For a task that left its session open (keepOpen) that means after stop_session. smoke_test, get_report after a skill run and a run_task that closes its own session have the log at once; in CI, read the report once more a few seconds later if evidence.logsPath is missing, as the script in Smoke tests in CI does.
Evidence and when links stop working
| Field | What it is | Lifetime |
|---|---|---|
evidence.reportSignedUrl | The HTML report as a link that opens without a key | The links stop working at urlsExpireAt. This is about 5 minutes after you asked for the report |
steps[].screenshotUrl | A screenshot of a failed step | The same time |
evidence.reportPath | Skill runs only. GET this path with your API key: it redirects to the HTML report | The redirect lasts 5 minutes |
evidence.recordingPath | The replay video of the session. Only when the session was recorded: always for smoke_test, and for run_task only with record: true | The path needs your key. The video is saved when the session ends |
evidence.logsPath | The full console and network log of the session | Needs your key. Present when the log was read |
Call get_report again to get new links. Download what you need to keep. See Evidence.
Task results
run_task answers with a short text, and the same data as structuredContent:
Here is a task that could not finish, because the page was an interstitial and not the app. The text:
Task stopped (blocked) in 2 steps, $0.0044, 10 s.
Reason: The AI model could not find a way forward (50% sure): The page is an ngrok interstitial. ...
Session sess_us_xxxxxxxxxxxxxxxxxxxxxxxx was closed.And the data, trimmed:
{
"sessionId": "sess_us_xxxxxxxxxxxxxxxxxxxxxxxx",
"sessionClosed": true,
"task": {
"ok": false,
"stoppedBy": "blocked",
"reason": "The AI model could not find a way forward (50% sure): The page is an ngrok interstitial. ...",
"steps": [
{ "op": "wait", "provider": "claude:claude-haiku-5-5", "ok": true, "ms": 3200, "costMicros": 140 }
],
"costMicros": 4400,
"ms": 10000,
"text": "..."
}
}| Field | Meaning |
|---|---|
ok | true only when the agent stopped because it was done (stoppedBy: done). |
answer | What the agent says it found. Present when it finished. |
stoppedBy | Why the task ended. See the table below. |
reason | A plain sentence about why it stopped, when it did not finish. |
limit | Which limit ended it, when one did: maxSteps, maxCostUsd or allowHosts. |
steps | One entry per action: op (click, type, navigate…), the element ref, ok, time in ms, cost and error. |
costMicros, ms | Cost in millionths of a dollar, and total time in milliseconds. |
text | The final page diff or snapshot text, cut short. |
sessionClosed | Whether the tool closed the browser. run_task closes a session it opened, unless you passed keepOpen. |
A goal task has no assertions of its own. ok: true means the agent believes it reached the goal. It does not prove your page is correct. Ask for a specific thing to check in the prompt, such as the exact text that must appear, and read answer. For a check with a fixed pass or fail, use smoke_test. To get a report for a task, call get_report with its taskId: the answer ends with that hint.
Still running
A task that takes longer than the wait (90 seconds for run_task, 30 seconds by default for get_task) is not an error. The tool answers:
{ "sessionId": "sess_us_...", "taskId": "tsk_...", "status": "running", "note": "still running: call get_task ..." }The browser keeps working and the session stays open. Call get_report with the taskId, or get_task with the sessionId and taskId, until it has finished. Neither closes the session: call stop_session when you are done.
get_task answers with status: finished and the stored task. Its steps and cost have the same meaning as above.
Stop reasons
stoppedBy | Meaning | Treat as |
|---|---|---|
done | The agent finished and gave an answer. | Pass or fail, from the answer |
blocked | The agent could not go on. For example a login wall it has no login for, or an address webagent refused to open. reason says which. limit: allowHosts means a site allowlist refused a navigation. | Could not test, unless the block is the app's fault |
stuck | Several steps in a row left the page unchanged or failed, or the agent kept repeating itself. | Often a real problem on the page: read reason and the failed steps |
budget | The task hit its step or cost cap. limit says which. | Could not test. Raise maxSteps (1 to 50) or split the goal |
captcha | The page showed a CAPTCHA. Webagent does not solve CAPTCHAs. | Could not test |
paused | A person took over the session. | Could not test |
error | Something failed inside the agent or the browser. | Could not test |
aborted | The task was stopped from outside, for example the session was closed. | Could not test |
unanswered | A question to the user waited with no answer. Over MCP the agent cannot answer, so this should not happen. | Could not test |
"Could not test" is not a bug in your app. An agent that reports a CAPTCHA or a budget stop as "the app is broken" is wrong. The agent setup snippet asks your agent to keep the two apart.
ok: false and isError
A task that stops without finishing is still a normal tool result in most cases. isError is set only when the agent could not test: stoppedBy is captcha, blocked, error, aborted or paused (or a capacity or timeout stop). A task that ended stuck, budget or unanswered has ok: false and no isError. Always read ok and stoppedBy, not only isError. get_report turns the same rule into a verdict: error for the first group, fail for the second.
Skill runs
skill_smoke_uat and the other skill_<name> tools start the run, wait for the verdict (30 seconds by default, options.waitSeconds up to 120) and answer with a summary and the raw run. For a test, smoke_test is easier: it answers with the test report instead. This is what a skill tool answers:
smoke-uat@1.2.1 run run_us_xxxxxxxxxxxxxxxxxxxxxxxx: failed in 7916 ms.
7 links checked (0 broken), 0 accessibility issues, 0 console errors
Reason: step 10 (assert 1 condition) failed: Expected text "Nonexistent heading" is not on the page
Counts: steps 13, cdpCalls 7, findings 0, warnings 0, assertions 6, failedSteps 1, findings.low 0, httpRequests 7, findings.high 0, findings.info 0, findings.medium 0, failedAssertions 1, findings.critical 0.
Failed steps (1):
- 9 assert 1 condition: Expected text "Nonexistent heading" is not on the page
Report (short-lived link): https://...
Full detail in structuredContent (no inline media); REST: GET /v1/skill-runs/run_us_...
For a pass/fail report call get_report with run_us_...This is the output of a real run on the Test Arena pricing page. The Reason: line counts steps from 1 and the Failed steps list counts from 0: the same step is "step 10" and "9". A run that passes has no Reason: and no failed steps, for example passed in 1229 ms. and the 7 links checked ... line.
Field in structuredContent | Meaning |
|---|---|
status | running, passed, failed, error, cancelled or denied |
summary, counts | One line and the totals: steps, failed steps, assertions, findings by severity |
result.steps | Each step: label, ok, ms and error |
result.findings | Problems the checks found, each with a severity and often a one-line fix |
result.reason | Why the run did not pass |
reportUrl | A signed link to the HTML report, with screenshots of failed steps |
hasReport | Whether a report exists |
What the statuses mean:
status | Meaning |
|---|---|
passed | Every check passed. |
failed | The test ran and found a problem. Read the failed steps and findings. |
error | The run could not finish, for example the browser or session failed. |
denied | The run needed a permission it was not given. |
cancelled | The run was stopped. |
running | Not finished yet. Call get_skill_run with the runId. It waits up to the waitSeconds you give (up to 120). |
Results leave out inline screenshots and video, and cut long text, so they fit in your agent's context. The full run is in GET /v1/skill-runs/<runId> and the report.
A skill tool or get_skill_run sets isError only for error, denied and cancelled: the runs that could not test. A failed run is a normal result: the app has a problem. For the verdict with console errors and failed network calls, call get_report with the runId.
Errors
A call that does not run comes back as a tool result with isError: true. The text is [code] message, and structuredContent.error holds the same as an object.
[navigation_blocked] ...| Code | What to do |
|---|---|
navigation_blocked | The address is not allowed: a private or localhost address. Use a public URL or a tunnel. |
capacity_exceeded | Too many sessions open, or no browser capacity. Stop old sessions with stop_session, or wait. |
invalid_input | The tool arguments were wrong. The message names the field. |
session_closed | The session already ended. Start a new one. |
not_found | No such session, task or run in this workspace. |
unauthorized, wrong_region | The key is bad, or it belongs to another region. |
rate_limited | Too many requests. Wait a moment and retry. |
The full list is in the error reference.
Evidence and how long it lasts
| Evidence | How you get it | How long |
|---|---|---|
| Live view | Dashboard, Sessions, open the session | Only while the session is open. run_task closes its own session at the end unless you set keepOpen. |
| Test report | smoke_test or get_report | Read it again any time. The links inside it work for about 5 minutes. See Evidence and when links stop working |
| Skill report (HTML) | reportSignedUrl in the test report, or reportUrl in a skill result | The link works for about 5 minutes. Open or save it right away. |
| Failed-step screenshots | screenshotUrl of a failed step in the test report, and inside the HTML report | The same time |
| Replay video | Always for smoke_test. For run_task and create_session, only with record: true | Saved when the session closes |
| Event log | GET /v1/sessions/<id>/logs after the session ends | REST only; see Evidence for how long it is kept |
| Share link | POST /v1/sessions/<id>/share: a link anyone can open | Between 1 minute and 7 days, as you choose |
A task result has no screenshots or console errors in it. The task report adds console errors and failed network calls from the session log. If you need proof with screenshots for a developer, run smoke_test: its report has a screenshot of every failed step and a recording. For a task, pass record: true to run_task to get a recording. Evidence has the full picture.