Skip to content

DoAnything ​

DoAnything is the open-ended browser task API and WebAgent's primary execution entry point. You provide a goal; the agent decides how to navigate, search, click, fill forms, and read pages in a real browser, then returns progress and a result. This page introduces the problems it solves and its core capabilities first, then the current call surface.

What it solves ​

  • Web tasks whose steps cannot be scripted: the goal spans multiple pages and the path shifts with page structure, so traditional scripts break on every redesign. DoAnything plans and adjusts the execution path at runtime — you maintain the goal, not the selectors.
  • Signed-in operations with no API: many back offices and member areas are web-only. DoAnything reuses login state from Profiles inside a controlled browser and works directly on the page.
  • Key actions need a human: confirmation requests surface as interaction events; the task continues after a human confirms, so you are not forced to choose between fully automated and fully manual.
  • Execution must be observable and traceable: every step streams back over SSE, screenshots can be captured as evidence, and a run can be canceled, reattached, or continued in the same browser context.

Core capabilities ​

CapabilityDescription
Autonomous executionCreate a run from one instruction; the agent plans the browser action sequence
Real browserNavigation, search, clicks, form filling, and reading happen in a controlled real browser
Context reusesession reuses the browser context; profileId reuses login state
Event streamSSE delivers progress, message, interaction, screenshot, and done
Human confirmationinteraction events carry confirmation requests, answered via interactionHandle
Evidence capturecapture.screenshots enables screenshots; the event stream keeps the execution trace
Run controllimits.maxDurationMinutes caps duration; cancel, pause, resume, and reattach are supported

Typical scenarios ​

  • Sign in to internal systems or SaaS back offices, query and verify data, and bring results back to your systems (see the Compliance risk agent).
  • Read and organize multiple pages on sites that require sign-in (see the Travel planning agent).
  • Check site content page by page against a defined rubric and produce a report (see the Brand consistency agent).

When to use it ​

  • The goal spans multiple pages and the steps should not be hardcoded.
  • You need login-state reuse, browser-context reuse, or human confirmation.
  • The output shape is flexible; the agent organizes the result around the goal.

For fixed-structure search results or research reports, use WebSearch or DeepResearch; for scheduled, long-lived page watching, use Track.

Current call ​

ts
const { token } = (await qoni.delegateToken({
  user: { id: process.env.QONI_USER_ID! },
  products: ["doAnything"],
})).data;

const run = await qoni.doAnything.run({
  token,
  prompt: "Open Hacker News and list the first five story titles and links.",
  capture: { screenshots: true },
  limits: { maxDurationMinutes: 10 },
  profileId: "prof_alice",
});
const result = await run.wait();
console.log(result.status, result.output);

run() returns a RunHandle; use run.id, not run["run_id"]. The old client.sessions, client.events, and runAsync() calls are not current SDK APIs.

REST surface ​

http
POST /api/v1/projects/{pid}/do_anything/runs
Authorization: Bearer wa_...
Content-Type: application/json

{"instructions":"Open Hacker News and list the first five stories.","max_duration_minutes":10}

Without session_id, the backend creates a session for the run. Pass an existing session_id to continue in the same browser context. The create response is 202 plus a run envelope.

Lifecycle and events ​

Run statuses are pending, running, awaiting_input, succeeded, failed, and canceled; terminal_reason can be done, failed, canceled, or expired.

http
GET /api/v1/projects/{pid}/do_anything/runs/{run_id}/events
Authorization: Bearer wa_...

The Node SDK normalizes events to progress, message, interaction, screenshot, and done. Low-level wire names are available under event.raw.event. Reconnect with Last-Event-ID.

ts
for await (const event of run.events()) {
  if (event.type === "interaction") {
    const interaction = run.interactionHandle(event.data);
    if (interaction.can("confirm")) await interaction.confirm();
  }
}

Follow-up and reconnect ​

ts
const next = await qoni.doAnything.run({
  token,
  prompt: "Open the first link and summarize its comments.",
  session: run.sessionRef,
});
const reattached = await qoni.doAnything.attach(run.id, { token });

The run-id REST surface also provides detail, cancel, intervene, messages, screenshots, pause, resume, and continue routes. Their exact request bodies are defined in the OpenAPI spec.