> ## Documentation Index
> Fetch the complete documentation index at: https://outcrawl.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

> Hand over a natural-language task, it finishes in a real browser.

export const OutcrawlStyles = () => {
  if (typeof document !== 'undefined' && !document.getElementById('outcrawl-overrides')) {
    const s = document.createElement('style');
    s.id = 'outcrawl-overrides';
    s.textContent = `
      /* Match the product's radius grid (4 / 6 / 8 / 9999), not Mintlify's default. */
      .rounded-sm { border-radius: 0.375rem !important; } /* 6px, --r-ctl */
      .rounded-md { border-radius: 0.375rem !important; } /* 6px, --r-ctl */
      .rounded-lg { border-radius: 0.5rem !important; }   /* 8px, --r-panel */
      .rounded-l-sm { border-top-left-radius: 0.375rem !important; border-bottom-left-radius: 0.375rem !important; }
      .rounded-r-sm { border-top-right-radius: 0.375rem !important; border-bottom-right-radius: 0.375rem !important; }
      .rounded-l-md { border-top-left-radius: 0.375rem !important; border-bottom-left-radius: 0.375rem !important; }
      .rounded-r-md { border-top-right-radius: 0.375rem !important; border-bottom-right-radius: 0.375rem !important; }
      .rounded-l-lg { border-top-left-radius: 0.5rem !important; border-bottom-left-radius: 0.5rem !important; }
      .rounded-r-lg { border-top-right-radius: 0.5rem !important; border-bottom-right-radius: 0.5rem !important; }

      /* Cards: never pure white in light mode, matching the one-big-card surface tone. */
      .card { background-color: #fcfcfc !important; border-radius: 0.5rem !important; }
      html.dark .card { background-color: #141311 !important; }

      /* Docs hero box */
      .oc-hero { background-color: #fcfcfc; border: 1px solid #e5e2dc; }
      html.dark .oc-hero { background-color: #141311; border-color: #26241f; }
      html.dark .oc-hero h1 { color: #edeae4; }

      /* Thin, transparent-track, hide-until-hover scrollbar. */
      ::-webkit-scrollbar { width: 6px; height: 6px; background-color: transparent; }
      ::-webkit-scrollbar-track { background-color: transparent; }
      ::-webkit-scrollbar-thumb { background-color: rgba(155, 155, 155, 0.5); border-radius: 10px; transition: opacity 0.3s ease; opacity: 0; }
      ::-webkit-scrollbar-thumb:hover { background-color: rgba(155, 155, 155, 0.7); }
      *:hover::-webkit-scrollbar-thumb,
      *:focus::-webkit-scrollbar-thumb,
      *:active::-webkit-scrollbar-thumb { opacity: 1; }
      * { scrollbar-width: thin; scrollbar-color: rgba(155, 155, 155, 0.5) transparent; }
    `;
    document.head.appendChild(s);
  }
  return null;
};

<OutcrawlStyles />

Submit a natural-language browser task and get an id back in milliseconds. The run is not held open on that call, hours are normal: read status separately, read results separately, cancel separately. In the SDKs those are `oc.agent.get(id)`, `oc.agent.results(id)` and `oc.agent.cancel(id)`, with the same names in Python. Use agents when a page needs decisions or interaction, not for plain reading, where [scrape](/docs/scrape/overview) is far cheaper.

An agent run is billed for the AI model's usage, browser time (1 credit per minute the run is open, paused time included) and proxy usage (2,000 credits per GB), in credits. A typical run costs **about 15 credits per minute** all in; that is an estimate, and the actual cost depends on the task. Driving a browser yourself with the SDK, without an agent, pays only browser time and proxy usage. See [pricing](/docs/billing/pricing).

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  import { Outcrawl } from '@outcrawl/sdk';

  const oc = new Outcrawl();
  const job = oc.agent({
    task: 'Report the title of the top story on Hacker News.',
    caps: { budget: '16.00' },
  });
  console.log(await job.id()); // store this to reach the run later
  const run = await job;
  console.log(run.status, run.data);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  import asyncio
  from outcrawl import Outcrawl

  async def main():
      async with Outcrawl() as oc:
          job = oc.agent(task="Report the title of the top story on Hacker News.", caps={"budget": "16.00"})
          print(await job.id())  # store this to reach the run later
          run = await job
          print(run["status"], run.get("data"))

  asyncio.run(main())
  ```

  ```bash curl theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  curl https://api.outcrawl.ai/v1/agent \
    -H "Authorization: Bearer ock_YOUR_KEY_ID.YOUR_SECRET" \
    -H "Content-Type: application/json" \
    -d '{
      "task": "Report the title of the top story on Hacker News.",
      "caps": { "budget": "16.00" }
    }'
  ```
</CodeGroup>

`caps.budget` is required, a hard ceiling on what the run is billed. A budget at or below 1 credit is refused before the run starts: a run spends model usage, browser time and proxy usage from its first step, so it would stop before reading anything. `caps.steps` and `caps.duration` are optional additional ceilings. This example task cost 5.0–7.7 credits on 2026-10-03 (n=33), so its 16.00 ceiling is twice the most it took; size yours from what your own tasks spend.

## Typed results

Give a run a JSON Schema and its answer comes back shaped to it instead of free text:

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  import { Outcrawl } from '@outcrawl/sdk';

  const oc = new Outcrawl();
  const typed = await oc.agent({
    task: 'Report the title of the top story on Hacker News.',
    caps: { steps: 20, budget: '16.00', duration: '5m' },
    schema: { type: 'object', properties: { title: { type: 'string' } }, required: ['title'] },
  });
  if (typed.status === 'completed') console.log(typed.data); // { title: '...' }
  else console.log(typed.status, typed.stopReason);          // capped, partial or failed: data may be absent
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  import asyncio
  from outcrawl import Outcrawl

  async def main():
      async with Outcrawl() as oc:
          typed = await oc.agent(
              task="Report the title of the top story on Hacker News.",
              caps={"steps": 20, "budget": "16.00", "duration": "5m"},
              schema={"type": "object", "properties": {"title": {"type": "string"}}, "required": ["title"]},
          )
          if typed["status"] == "completed":
              print(typed["data"])  # {'title': '...'}
          else:
              print(typed["status"], typed.get("stopReason"))  # capped, partial or failed: data may be absent

  asyncio.run(main())
  ```

  ```bash curl theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  curl https://api.outcrawl.ai/v1/agent \
    -H "Authorization: Bearer ock_YOUR_KEY_ID.YOUR_SECRET" \
    -H "Content-Type: application/json" \
    -d '{
      "task": "Report the title of the top story on Hacker News.",
      "caps": { "steps": 20, "budget": "16.00", "duration": "5m" },
      "schema": { "type": "object", "properties": { "title": { "type": "string" } }, "required": ["title"] }
    }'
  ```
</CodeGroup>

## Cancel

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  import { Outcrawl } from '@outcrawl/sdk';

  const oc = new Outcrawl();
  const run = await oc.agent.cancel('<id>');
  console.log(run.status);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  import asyncio
  from outcrawl import Outcrawl

  async def main():
      async with Outcrawl() as oc:
          run = await oc.agent.cancel("<id>")
          print(run["status"])

  asyncio.run(main())
  ```

  ```bash curl theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  curl -X POST https://api.outcrawl.ai/v1/agent/<id>/cancel \
    -H "Authorization: Bearer ock_YOUR_KEY_ID.YOUR_SECRET"
  ```
</CodeGroup>

Stops a run and answers it as it stands, so cancelling a run that already finished is not an error. Work already done stays billed: `caps.budget` is the spending limit, cancel is the stop button.

<CardGroup cols={3}>
  <Card title="Monitoring" icon="activity" href="/docs/agents/monitoring">
    Status, the event log, results, and webhooks.
  </Card>

  <Card title="Human in the loop" icon="user-check" href="/docs/agents/human-in-the-loop">
    Take the wheel of a live run, and hand it back.
  </Card>

  <Card title="Files" icon="paperclip" href="/docs/agents/files">
    Attach a file to a run.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.