Skip to main content
TinyFish Web Agent offers three ways to run automations. Each endpoint serves a different need. Pick the one that matches how you want to handle the request and response.

The Three Endpoints

EndpointPatternBest For
/runSynchronousQuick tasks, simple integrations
/run-asyncStart then checkLong tasks, batch processing
/run-sseLive updatesReal-time progress, user-facing apps

Synchronous: /run

Pattern: Send request → Wait → Get result The simplest approach. You call the API, it blocks until the automation completes, then returns the result.
import { TinyFish } from "@tiny-fish/sdk";

const client = new TinyFish();

const run = await client.agent.run({
  url: "https://example.com",
  goal: "Extract the page title",
});

console.log(run.result); // Your data
Runs created via /run cannot be cancelled. The request blocks until the automation completes, so there is no window to issue a cancellation. If you need the ability to cancel runs, use /run-async or /run-sse instead.
  • Tasks that complete in under 30 seconds
  • Simple scripts and one-off automations
  • When you don’t need progress updates

Asynchronous: /run-async

Pattern: Send request → Get run ID → Poll for result The request returns immediately with a run_id. You then poll a separate endpoint to check status and get the result when ready. 1. Start the automation
import { TinyFish } from "@tiny-fish/sdk";

const client = new TinyFish();

const queued = await client.agent.queue({
  url: "https://example.com",
  goal: "Extract all product data",
});

if (queued.error) {
  throw new Error(`Failed to queue run: ${queued.error.message}`);
}

const runId = queued.run_id;
2. Poll for the result
const run = await client.runs.get(runId);
// run.status: PENDING, RUNNING, COMPLETED, FAILED, or CANCELLED
// run.result: Your data (when COMPLETED)
3. Cancel a run (optional) If you need to stop a run before it completes, send a POST to the cancel endpoint:
await fetch(`https://agent.tinyfish.ai/v1/runs/${runId}/cancel`, {
  method: "POST",
  headers: { "X-API-Key": process.env.TINYFISH_API_KEY },
});
Learn more about run statuses and lifecycle in Runs.
  • Long-running automations (30+ seconds)
  • Batch processing multiple URLs
  • Fire-and-forget workflows
  • When you need to track runs separately

Streaming: /run-sse

Pattern: Send request → Receive event stream → Process events as they arrive Uses Server-Sent Events (SSE) to push updates to you in real-time. You’ll receive events for each action the browser takes, plus a streaming URL you can embed in an iframe to watch the automation live. 1. Start the automation and read events
import { TinyFish, EventType } from "@tiny-fish/sdk";

const client = new TinyFish();

const stream = await client.agent.stream({
  url: "https://example.com",
  goal: "Extract all product data",
});

for await (const event of stream) {
  console.log(event.type, event);
}

Event Types

EventDescription
STARTEDAutomation has begun, includes run_id
STREAMING_URLURL to watch the browser live (valid 24hrs)
PROGRESSBrowser action taken (click, type, scroll, etc.)
HEARTBEATConnection keep-alive (no action needed)
COMPLETEAutomation finished, includes status and result

Cancelling an SSE Run

You can cancel a streaming run using the run_id from the STARTED event:
await fetch(`https://agent.tinyfish.ai/v1/runs/${run_id}/cancel`, {
  method: "POST",
  headers: { "X-API-Key": process.env.TINYFISH_API_KEY },
});

Handling Events

Use this pattern to process each event type as the automation progresses.
import { TinyFish, EventType, RunStatus } from "@tiny-fish/sdk";

const client = new TinyFish();

const stream = await client.agent.stream(
  { url: "https://example.com", goal: "Extract all product data" },
  {
    onStarted: (e) => console.log(`Run started: ${e.run_id}`),
    onStreamingUrl: (e) => console.log(`Watch live: ${e.streaming_url}`),
    onProgress: (e) => console.log(`Action: ${e.purpose}`),
    onComplete: (e) => {
      if (e.status === RunStatus.COMPLETED) {
        console.log("Result:", e.result);
      } else {
        console.error(e.error?.message || "Automation failed");
      }
    },
  },
);

for await (const event of stream) {
  // Callbacks fire automatically during iteration
}
  • User-facing apps (show progress)
  • When you want to watch the browser live
  • Debugging and development
  • Long tasks where you want visibility

Quick Decision Guide

1

Need real-time progress updates?

Yes → Use /run-sse
2

Task takes longer than 30 seconds?

Yes → Use /run-async + polling
3

Submitting multiple tasks at once?

Yes → Use /run-async (parallel submission)
4

Simple, quick task?

Use /run (synchronous)

Comparison Table

Feature/run/run-async/run-sse
Response typeFinal resultRun IDEvent stream
Progress updatesNoNo (poll status)Yes
Streaming URLIn responsePoll to getIn events
CancellableNoYesYes
Best forQuick tasksBatch/long tasksReal-time UI
ComplexityLowMediumMedium

Runs

Understand the automation lifecycle

API Reference

Full endpoint specifications