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

# Browser API Reference

> Complete reference for the Browser API endpoints

## Endpoints

| Method   | Path                                           | Description                 |
| -------- | ---------------------------------------------- | --------------------------- |
| `POST`   | `https://api.browser.tinyfish.ai`              | Create a browser session    |
| `DELETE` | `https://api.browser.tinyfish.ai/{session_id}` | Terminate a browser session |

All requests require an `X-API-Key` header. See [Authentication](/authentication).

<Note>
  The SDKs (`tinyfish` for Python and `@tiny-fish/sdk` for TypeScript) target `https://agent.tinyfish.ai/v1/browser` by default, while the REST host documented here is `https://api.browser.tinyfish.ai`. Both hosts are supported and behave identically.
</Note>

<Note>
  Session creation typically takes 10-30 seconds. Set your HTTP client timeout to at least 60 seconds. Direct Browser API sessions are isolated; use [Browser Context Profiles](/agent-api/browser-context-profiles) when you need reusable cookies or storage.
</Note>

***

## Request

```json theme={null}
{
  "url": "https://www.tinyfish.ai",
  "timeout_seconds": 300
}
```

### Parameters

<ParamField body="url" type="string">
  Target URL the session will navigate to on startup. Bare domains (e.g. `tinyfish.ai`) are automatically prefixed with `https://`. Omit to start at `about:blank`.
</ParamField>

<ParamField body="timeout_seconds" type="integer">
  Inactivity timeout in seconds (5–86400). Defaults to your plan maximum.
</ParamField>

***

## Response

On success, returns `201 Created` with a JSON body containing `session_id`, `cdp_url`, and `base_url`.

```json theme={null}
{
  "session_id": "br-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "cdp_url": "wss://example.tinyfish.io/cdp",
  "base_url": "https://example.tinyfish.io"
}
```

<ResponseField name="session_id" type="string">
  Unique identifier for this session.
</ResponseField>

<ResponseField name="cdp_url" type="string">
  WebSocket URL for browser connection. Pass this to Playwright's `connect_over_cdp` or any CDP client.
</ResponseField>

<ResponseField name="base_url" type="string">
  HTTPS base URL for the session. Use to access session endpoints such as `/pages`.
</ResponseField>

***

## DELETE — Terminate a Session

```bash theme={null}
DELETE https://api.browser.tinyfish.ai/{session_id}
```

Terminates the session immediately. If the session is already ended this call is a no-op and still returns `204`.

### Path Parameters

<ParamField path="session_id" type="string" required>
  The `session_id` returned when the session was created.
</ParamField>

### Response

Returns `204 No Content` with an empty body on success.

### Error Codes

| HTTP Status | Error Code                            | Cause                                                          |
| ----------- | ------------------------------------- | -------------------------------------------------------------- |
| 400         | `INVALID_INPUT`                       | `session_id` is missing or empty.                              |
| 401         | `MISSING_API_KEY` / `INVALID_API_KEY` | Missing or invalid `X-API-Key`.                                |
| 404         | `NOT_FOUND`                           | Session does not exist or belongs to a different API key.      |
| 502         | `INTERNAL_ERROR`                      | Browser infrastructure failed to terminate the session. Retry. |

***

## Debugging — Open DevTools Inspector

Poll `GET {base_url}/pages` and open the `devtoolsFrontendUrl` of the first non-blank page to inspect the live browser session.

<CodeGroup>
  ```python Python theme={null}
  async def get_inspector_url(base_url: str) -> str:
      async with httpx.AsyncClient() as client:
          for _ in range(20):
              pages = (await client.get(f"{base_url}/pages", timeout=5)).json()
              nav = next((p for p in pages if p.get("url") not in ("", "about:blank", "about:newtab")), None)
              if nav:
                  return nav["devtoolsFrontendUrl"]
              await asyncio.sleep(1)
      raise TimeoutError("navigation never completed")
  ```

  ```typescript TypeScript theme={null}
  async function getInspectorUrl(baseUrl: string): Promise<string> {
    for (let i = 0; i < 20; i++) {
      const res = await fetch(`${baseUrl}/pages`);
      const pages: { url: string; devtoolsFrontendUrl: string }[] = await res.json();
      const nav = pages.find(p => !['', 'about:blank', 'about:newtab'].includes(p.url));
      if (nav) return nav.devtoolsFrontendUrl;
      await new Promise(r => setTimeout(r, 1000));
    }
    throw new Error('navigation never completed');
  }
  ```
</CodeGroup>

<Note>
  The page starts at `about:blank` and navigates asynchronously — skip blank pages when polling to get the correct inspector URL.
</Note>

***

## Session Lifecycle

| Behavior                 | Details                                                                                                                                                                                        |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Startup navigation**   | If `url` was provided at session creation, the browser navigates there immediately. The 201 response is returned before navigation completes — the page may still be loading when you connect. |
| **Inactivity timeout**   | Sessions automatically terminate after the configured inactivity timeout. A session is considered inactive when no CDP commands are being sent.                                                |
| **Explicit termination** | Send `DELETE https://api.browser.tinyfish.ai/{session_id}` to terminate a session immediately. Returns `204 No Content` on success. Deleting an already-ended session is idempotent.           |
| **Session isolation**    | Each direct Browser API session is isolated. For reusable cookies and storage, use [Browser Context Profiles](/agent-api/browser-context-profiles).                                            |

***

## SDK Methods

<CodeGroup>
  ```python Python theme={null}
  from tinyfish import TinyFish

  client = TinyFish()
  session = client.browser.sessions.create(url="https://www.tinyfish.ai")
  print(session.session_id)
  print(session.cdp_url)
  ```

  ```typescript TypeScript theme={null}
  import { TinyFish } from "@tiny-fish/sdk";

  const client = new TinyFish();
  const session = await client.browser.sessions.create({
    url: "https://www.tinyfish.ai",
  });
  console.log(session.session_id);
  console.log(session.cdp_url);
  ```
</CodeGroup>

***

## End-to-End Example

Create a session, connect with Playwright, take a screenshot, and extract the page title.

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from tinyfish import TinyFish
  from playwright.async_api import async_playwright

  client = TinyFish()

  async def main():
      # 1. Create a browser session
      session = client.browser.sessions.create(url="https://scrapeme.live/shop")

      # 2. Connect via Playwright CDP
      async with async_playwright() as p:
          browser = await p.chromium.connect_over_cdp(session.cdp_url)
          await asyncio.sleep(2)  # let startup navigation settle

          page = browser.contexts[0].pages[0]
          await page.wait_for_load_state("domcontentloaded")

          # 3. Interact with the page
          print(await page.title())
          await page.screenshot(path="shop.png")

      # Session auto-cleans up after 1 hour of inactivity

  asyncio.run(main())
  ```

  ```typescript TypeScript theme={null}
  import { TinyFish } from "@tiny-fish/sdk";
  import { chromium } from "playwright";

  const client = new TinyFish();

  // 1. Create a browser session
  const session = await client.browser.sessions.create({
    url: "https://scrapeme.live/shop",
  });

  // 2. Connect via Playwright CDP
  const browser = await chromium.connectOverCDP(session.cdp_url);
  await new Promise((r) => setTimeout(r, 2000)); // let startup navigation settle

  const page = browser.contexts()[0].pages()[0];
  await page.waitForLoadState("domcontentloaded");

  // 3. Interact with the page
  console.log(await page.title());
  await page.screenshot({ path: "shop.png" });

  // Session auto-cleans up after 1 hour of inactivity
  ```
</CodeGroup>

***

## Error Reference

| HTTP Status | Error Code                            | Cause                                               | Resolution                                                                                                    |
| ----------- | ------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| 400         | `INVALID_INPUT`                       | `url` field is not a valid URL.                     | Check the `details` field in the error response for specifics.                                                |
| 401         | `MISSING_API_KEY` / `INVALID_API_KEY` | Missing or invalid `X-API-Key` header.              | Verify your API key at the [dashboard](https://agent.tinyfish.ai/api-keys).                                   |
| 402         | `INSUFFICIENT_CREDITS`                | No credits or active subscription.                  | Add credits or upgrade your plan.                                                                             |
| 404         | `NOT_FOUND`                           | Browser API is not available on your plan.          | Contact support to enable access.                                                                             |
| 500         | `INTERNAL_ERROR`                      | Unexpected server error.                            | Retry after a brief delay. If persistent, check [agent.tinyfish.ai/status](https://agent.tinyfish.ai/status). |
| 502         | `INTERNAL_ERROR`                      | Browser infrastructure failed to start the session. | Retry — this is usually transient.                                                                            |

## Related

<CardGroup cols={2}>
  <Card title="Browser Overview" icon="browser" href="/browser-api">
    First request, success shape, and product routing
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    API key setup
  </Card>

  <Card title="Browser Context Profiles" icon="window" href="/agent-api/browser-context-profiles">
    Persist login state for future Agent API runs
  </Card>

  <Card title="Error Codes" icon="triangle-exclamation" href="/error-codes">
    Full list of API error codes
  </Card>

  <Card title="Key Concepts" icon="plug" href="/key-concepts/endpoints">
    Understand where Browser fits in the overall API surface
  </Card>
</CardGroup>
