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

> ## Agent Instructions
> The Zenrows API (Fetch, Extract via extract=auto, and Batch) is described in OpenAPI 3.1 at https://www.zenrows.com/openapi.json and listed in the RFC 9727 API catalog at https://www.zenrows.com/.well-known/api-catalog. Use the spec for exact parameter names and types.

# Build a browser agent with Zenrows

> Build an AI agent that browses on its own: it opens pages, logs in, clicks and reads in Zenrows Browser, with no agent framework to install.

Give a model the Zenrows browser tools and it becomes a browser agent: it opens a page in Zenrows Browser, the browser for agents, decides each next step from what it sees, and clicks, types and reads until the task is done. The Anthropic and OpenAI APIs call the Zenrows MCP server for you, so the whole agent is one API request, with no framework and no browser to run.

**Uses:** [Browser](/browser-sessions/introduction) through the [Zenrows MCP server](/mcp/overview) and its `browser_*` tools

## Ask your AI agent

With the [Zenrows MCP server](/mcp/overview) connected to Claude, Cursor or any MCP client, paste this prompt. Your agent picks the right Zenrows tools and settings on its own.

```text theme={"dark"}
Use the Zenrows browser to log in at https://www.scrapingcourse.com/login with
admin@example.com and password, and tell me the first three products on the page
you land on. Close the browser session when you're done.
```

## How it works

1. You send the task to the model with the Zenrows MCP server attached as a tool source.
2. The model calls `browser_navigate`, which opens a cloud browser session and returns its `session_id`.
3. The model reads the page and acts on it with the other `browser_*` tools: `browser_fill`, `browser_click`, `browser_press_key`, `browser_wait_for_selector`, `browser_get_text`, `browser_query_selector_all`, `browser_screenshot` and more.
4. It repeats step 3 until it has the answer, then calls `browser_close` and replies.

The LLM provider runs this loop on its side and calls `https://mcp.zenrows.com/mcp` with your Zenrows API key. Your code sends one request and reads one response.

## Build the agent

Set `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`, and replace `YOUR_ZENROWS_API_KEY` with your key. The tool list limits the agent to the browser tools, so it browses instead of scraping.

<CodeGroup>
  ```python Anthropic (Python) theme={"dark"}
  import anthropic

  ZENROWS_API_KEY = "YOUR_ZENROWS_API_KEY"
  BROWSER_TOOLS = [
      "browser_navigate", "browser_click", "browser_fill", "browser_press_key",
      "browser_wait_for_selector", "browser_get_text", "browser_query_selector_all",
      "browser_screenshot", "browser_close",
  ]

  client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY

  response = client.beta.messages.create(
      model="claude-opus-5-5",
      max_tokens=16000,
      betas=["mcp-client-2025-11-20", "server-side-fallback-2026-07-01"],
      fallbacks="default",
      output_config={"effort": "high"},
      system=(
          "You control a cloud browser through the Zenrows tools. Open pages with "
          "browser_navigate, act with the other browser tools, and call browser_close "
          "on every session you open before you answer."
      ),
      mcp_servers=[
          {
              "type": "url",
              "url": "https://mcp.zenrows.com/mcp",
              "name": "zenrows",
              "authorization_token": ZENROWS_API_KEY,
          }
      ],
      tools=[
          {
              "type": "mcp_toolset",
              "mcp_server_name": "zenrows",
              "default_config": {"enabled": False},
              "configs": {name: {"enabled": True} for name in BROWSER_TOOLS},
          }
      ],
      messages=[
          {
              "role": "user",
              "content": "Log in at https://www.scrapingcourse.com/login with admin@example.com "
                         "and password, and tell me the first three products on the page you land on.",
          }
      ],
  )

  for block in response.content:
      if block.type == "mcp_tool_use":
          print("step:", block.name, block.input)
      elif block.type == "text":
          print(block.text)
  ```

  ```javascript Anthropic (Node.js) theme={"dark"}
  import Anthropic from "@anthropic-ai/sdk";

  const ZENROWS_API_KEY = "YOUR_ZENROWS_API_KEY";
  const BROWSER_TOOLS = [
    "browser_navigate", "browser_click", "browser_fill", "browser_press_key",
    "browser_wait_for_selector", "browser_get_text", "browser_query_selector_all",
    "browser_screenshot", "browser_close",
  ];

  const client = new Anthropic(); // reads ANTHROPIC_API_KEY

  const response = await client.beta.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 16000,
    betas: ["mcp-client-2025-11-20", "server-side-fallback-2026-07-01"],
    fallbacks: "default",
    output_config: { effort: "high" },
    system:
      "You control a cloud browser through the Zenrows tools. Open pages with " +
      "browser_navigate, act with the other browser tools, and call browser_close " +
      "on every session you open before you answer.",
    mcp_servers: [
      {
        type: "url",
        url: "https://mcp.zenrows.com/mcp",
        name: "zenrows",
        authorization_token: ZENROWS_API_KEY,
      },
    ],
    tools: [
      {
        type: "mcp_toolset",
        mcp_server_name: "zenrows",
        default_config: { enabled: false },
        configs: Object.fromEntries(BROWSER_TOOLS.map((name) => [name, { enabled: true }])),
      },
    ],
    messages: [
      {
        role: "user",
        content:
          "Log in at https://www.scrapingcourse.com/login with admin@example.com " +
          "and password, and tell me the first three products on the page you land on.",
      },
    ],
  });

  for (const block of response.content) {
    if (block.type === "mcp_tool_use") console.log("step:", block.name, block.input);
    else if (block.type === "text") console.log(block.text);
  }
  ```

  ```python OpenAI (Python) theme={"dark"}
  from openai import OpenAI

  ZENROWS_API_KEY = "YOUR_ZENROWS_API_KEY"
  BROWSER_TOOLS = [
      "browser_navigate", "browser_click", "browser_fill", "browser_press_key",
      "browser_wait_for_selector", "browser_get_text", "browser_query_selector_all",
      "browser_screenshot", "browser_close",
  ]

  client = OpenAI()  # reads OPENAI_API_KEY

  response = client.responses.create(
      model="gpt-5",
      instructions=(
          "You control a cloud browser through the Zenrows tools. Open pages with "
          "browser_navigate, act with the other browser tools, and call browser_close "
          "on every session you open before you answer."
      ),
      tools=[
          {
              "type": "mcp",
              "server_label": "zenrows",
              "server_url": "https://mcp.zenrows.com/mcp",
              "authorization": ZENROWS_API_KEY,
              "allowed_tools": BROWSER_TOOLS,
              "require_approval": "never",
          }
      ],
      input="Log in at https://www.scrapingcourse.com/login with admin@example.com "
            "and password, and tell me the first three products on the page you land on.",
  )

  print(response.output_text)
  ```
</CodeGroup>

Install the SDK first: `pip install anthropic`, `npm install @anthropic-ai/sdk` or `pip install openai`. The Anthropic examples also turn on server-side fallbacks, which hand a declined request to another Claude model automatically.

## Example output

These are the browser steps behind the task, run against the Zenrows MCP server with the same tools the agent calls:

```text theme={"dark"}
browser_navigate {"url": "https://www.scrapingcourse.com/login"} -> {"session_id": "851298be-...", "title": "Login Challenge to Learn Web Scraping - ScrapingCourse.com"}
browser_fill {"selector": "#email", "value": "admin@example.com"} -> {"ok": true}
browser_fill {"selector": "#password", "value": "password"} -> {"ok": true}
browser_press_key {"key": "Enter"} -> {"ok": true}
browser_wait_for_selector {"selector": ".product-name"} -> {"ok": true}
browser_query_selector_all {"selector": ".product-name"} -> {"elements": [{"text": "Chaz Kangeroo Hoodie", ...}, {"text": "Teton Pullover Hoodie", ...}, {"text": "Bruno Compete Hoodie", ...}, ...]}
browser_close {} -> {"ok": true}
```

The model picks its own selectors and order, so its steps can differ from this run. Its answer names the three products: Chaz Kangeroo Hoodie, Teton Pullover Hoodie and Bruno Compete Hoodie.

## Customize it

| Change | How |
| - | - |
| Browse from a country | Say it in the task, for example "as a visitor from Germany". The model passes the country to `browser_navigate`, see [Country](/browser-sessions/features/country) |
| Read pages fast and browse only when needed | Add `scrape` and `extract` to the tool list, see [Fetch first, open a Browser when a task needs interaction](/academy/pipelines/fetch-with-browser-fallback) |
| Run steps in one call | Add `browser_batch` to the tool list. The model sends several actions in one request |
| Screenshots or PDFs in the answer | Keep `browser_screenshot`, add `browser_generate_pdf`, see [Take screenshots and save pages as PDF](/academy/browser/screenshots-and-pdfs) |
| More tools | The full list is in the [MCP tool reference](/mcp/tool-reference): tabs, cookies, local storage, scrolling, drag and drop, and more |
| Your own loop and logging | Run the Zenrows MCP server from your code with any MCP client library, or write Playwright yourself, see [Connect Playwright or Puppeteer to Zenrows Browser](/academy/browser/connect-playwright-and-puppeteer) |

## Troubleshooting

* **The agent answers without opening a page**: name the action in the task ("Log in at...", "Open...") and keep the system prompt that tells it to use the browser tools.
* **The answer ends mid-task**: the task needs more steps. Raise `max_tokens`, or split the job into two requests.
* **`401` from the Zenrows server**: the `authorization_token` or `authorization` value isn't a valid Zenrows API key. Copy it again from the [dashboard](https://app.zenrows.com/dashboard).
* **A session stays open after an error**: keep "call browser\_close on every session you open" in the system prompt. Sessions also end on their own when their time runs out.

## Related recipes

<CardGroup cols={2}>
  <Card title="Let your AI assistant browse with Browser tools" icon="message-chatbot" href="/academy/browser/ai-assistant-browsing">
    The same tools from Claude, Cursor or any chat client.
  </Card>

  <Card title="Fetch first, open a Browser when a task needs interaction" icon="arrows-split" href="/academy/pipelines/fetch-with-browser-fallback">
    Give your agent fast reading and a full browser.
  </Card>

  <Card title="Build a research agent with live web data" icon="robot" href="/academy/pipelines/research-agent">
    An agent that reads and cites live pages.
  </Card>

  <Card title="Connect Playwright or Puppeteer to Zenrows Browser" icon="click" href="/academy/browser/connect-playwright-and-puppeteer">
    Drive the browser from your own code.
  </Card>
</CardGroup>


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