> ## 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.

# Human in the loop

> Take the wheel of a live run, and hand it back.

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 />

Nothing sends a running agent new instructions. A person acts on a live run in two ways: answering a question the run asked, and control, taking the browser and handing it back.

## Control

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

  const oc = new Outcrawl();
  const run = oc.agent.job('<id>');
  let state = await run.control('take'); // the run holds at its next step boundary
  while (state.pause?.reason !== 'control') {
    await new Promise((wake) => setTimeout(wake, 2000));
    state = await run.status();
  }
  console.log(state.pause.viewerUrl); // open it, press take control in the player

  // ... do the step yourself ...

  await run.control('release'); // the agent resumes on whatever page you left it on
  ```

  ```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 = oc.agent.job("<id>")
          state = await run.control("take")  # the run holds at its next step boundary
          while (state.get("pause") or {}).get("reason") != "control":
              await asyncio.sleep(2)
              state = await run.status()
          print(state["pause"].get("viewerUrl"))  # open it, press take control in the player

          # ... do the step yourself ...

          await run.control("release")  # the agent resumes on whatever page you left it on

  asyncio.run(main())
  ```

  ```bash curl theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  curl -X POST https://api.outcrawl.ai/v1/agent/<id>/control \
    -H "Authorization: Bearer ock_YOUR_KEY_ID.YOUR_SECRET" \
    -H "Content-Type: application/json" \
    -d '{"action": "take"}'
  ```
</CodeGroup>

Asks for the wheel of a live run. The run finishes the step it is on, then holds with the browser still open, and its status becomes `paused`. `pause.viewerUrl` on the run is the player for that session: open it and press **take control** there to drive the page yourself. It is absent when the run was submitted with `record: false`. Hand the wheel back with `control('release')` and the agent resumes from whatever page you left it on, not from where it was.

While you hold the wheel, whether after `control('take')` or by driving in the live viewer, the run bills browser time (1 credit a minute) and proxy usage only, with no model usage, until you hand it back. See [pricing](/docs/billing/pricing).

Use it for a step you would rather do yourself, a login you will not automate, a form only you should complete, not to stop a run (that is [`agent.cancel`](/docs/agents/overview#cancel)).

## Answer

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

  const oc = new Outcrawl();
  await oc.agent.answer('<id>', 'the blue one');
  ```

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

  async def main():
      async with Outcrawl() as oc:
          await oc.agent.answer("<id>", "the blue one")

  asyncio.run(main())
  ```

  ```bash curl theme={"theme":{"light":"github-light","dark":"catppuccin-mocha"}}
  curl -X POST https://api.outcrawl.ai/v1/agent/<id>/answer \
    -H "Authorization: Bearer ock_YOUR_KEY_ID.YOUR_SECRET" \
    -H "Content-Type: application/json" \
    -d '{"answer": "the blue one"}'
  ```
</CodeGroup>

When a run needs something only you know, it parks: its status becomes `paused` with `pause.reason` set to `question`, `pause.question` holding what it asked, `pause.options` the replies it suggests (any answer is accepted) and `pause.expiresAt` when it stops waiting. Answer it and the run carries on from where it stopped. A question nobody answers by `pause.expiresAt` is answered "nobody replied" and the run decides what to do without it.

<Note>
  A run that can pay may ask two structured questions, in `pause.ask`. An `approval` question (a purchase above your workspace's approval amount) is answered with `{"approve": true}` or `{"approve": false}`; one nobody answers in time fails that purchase with `approval_timed_out` and nothing is bought. A `secret` question (a card, a billing profile or a security code) is never answered here: send the value as a run secret named `pause.ask.for`, and an answer carrying it is refused with `secret_in_answer`.
</Note>

<Warning>
  Control is the only way to redirect what a live run does. Nothing sends a running agent new instructions mid-task, cancel and resubmit for that.
</Warning>


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