SPB Git

Repository Public

browser-use-tool.md 104.8 KB 1,582 lines markdown

1---2title: Browser use tool3url: https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool4description: Let Claude navigate, read, and interact with webpages in your own browser environment with the browser use tool.5---67## Compatibility8- [ZDR](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention): eligible (excludes [Covered Models](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements))9- Supported models: `claude-fable-5-1`, `claude-mythos-5-1`, `claude-fable-5`, `claude-mythos-5`, `claude-opus-5`, `claude-sonnet-5`, `claude-opus-4-8`10- Platforms: Claude API, Google Cloud; not available on Claude Platform on AWS, Amazon Bedrock, Microsoft Foundry1112The browser use tool lets Claude navigate, read, and interact with webpages in a browser that your application runs. Claude works with the page both through its structure (the accessibility tree, elements, forms, and tabs) and through screenshots and viewport coordinates.1314The tool is an Anthropic-defined [client toolset](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference#client-toolsets): one `browser_toolset_20260801` entry in `tools` gives Claude 27 member tools by default, such as `navigate`, `read_page`, `left_click`, and `screenshot`, plus four more when you [enable them](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#enable-optional-member-tools). Your application runs every call against its own browser automation; nothing runs on Anthropic's side. The tool isn't currently available in [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/tools).1516Choose browser use when the task stays inside webpages and means acting on them, or when pages build their content with JavaScript. When a task needs a whole desktop, use the [computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool), which works through screenshots and coordinates alone. For reading pages you can point Claude to, or finding sources on the web, the [web fetch tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-fetch-tool) and [web search tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool) are lighter. They're [server tools](https://platform.claude.com/docs/en/agents-and-tools/tool-use/server-tools) that the API runs for you, with no browser to operate.1718With browser use, Claude reads and acts on live webpages, so everything a page supplies is untrusted input and the actions Claude takes can have real effects. See [Security considerations](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#security-considerations) before you deploy.1920## Quick start2122The browser use tool is available on the Claude API and [Google Cloud](https://platform.claude.com/docs/en/build-with-claude/claude-on-vertex-ai): add one entry of type `browser_toolset_20260801`, with no `name`, to the `tools` array of a [Messages API](https://platform.claude.com/docs/en/api/messages/create) request.2324<CodeGroup>25  ```bash cURL26  curl https://api.anthropic.com/v1/messages \27    -H "content-type: application/json" \28    -H "x-api-key: $ANTHROPIC_API_KEY" \29    -H "anthropic-version: 2023-06-01" \30    -d '{31      "model": "claude-opus-5",32      "max_tokens": 2048,33      "tools": [34        {35          "type": "browser_toolset_20260801"36        }37      ],38      "messages": [39        {40          "role": "user",41          "content": "Open example.com/docs and tell me how to get started."42        }43      ]44    }'45  ```4647  ```bash CLI48  ant messages create <<'YAML'49  model: claude-opus-550  max_tokens: 204851  tools:52    - type: browser_toolset_2026080153  messages:54    - role: user55      content: Open example.com/docs and tell me how to get started.56  YAML57  ```5859  ```python Python60  client = anthropic.Anthropic()6162  response = client.messages.create(63      model="claude-opus-5",64      max_tokens=2048,65      tools=[{"type": "browser_toolset_20260801"}],66      messages=[67          {68              "role": "user",69              "content": "Open example.com/docs and tell me how to get started.",70          }71      ],72  )73  print(response)74  ```7576  ```typescript TypeScript77  const client = new Anthropic();7879  const response = await client.messages.create({80    model: "claude-opus-5",81    max_tokens: 2048,82    tools: [{ type: "browser_toolset_20260801" }],83    messages: [84      {85        role: "user",86        content: "Open example.com/docs and tell me how to get started."87      }88    ]89  });9091  console.log(response);92  ```9394  ```csharp C#95  var client = new AnthropicClient();9697  var parameters = new MessageCreateParams98  {99      Model = Model.ClaudeOpus5,100      MaxTokens = 2048,101      Tools = [new BrowserToolset20260801()],102      Messages =103      [104          new MessageParam105          {106              Role = Role.User,107              Content = "Open example.com/docs and tell me how to get started.",108          },109      ],110  };111112  var response = await client.Messages.Create(parameters);113  Console.WriteLine(response);114  ```115116  ```go Go117  client := anthropic.NewClient()118119  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{120  	Model:     anthropic.ModelClaudeOpus5,121  	MaxTokens: 2048,122  	Tools: []anthropic.ToolUnionParam{123  		{OfBrowserToolset20260801: &anthropic.BrowserToolset20260801Param{}},124  	},125  	Messages: []anthropic.MessageParam{126  		anthropic.NewUserMessage(anthropic.NewTextBlock("Open example.com/docs and tell me how to get started.")),127  	},128  })129  if err != nil {130  	log.Fatal(err)131  }132  fmt.Println(response.RawJSON())133  ```134135  ```java Java136  import com.anthropic.models.messages.BrowserToolset20260801;137  // ...138139  void main() {140      AnthropicClient client = AnthropicOkHttpClient.fromEnv();141142      MessageCreateParams params = MessageCreateParams.builder()143          .model(Model.CLAUDE_OPUS_5)144          .maxTokens(2048L)145          .addTool(BrowserToolset20260801.builder().build())146          .addUserMessage("Open example.com/docs and tell me how to get started.")147          .build();148149      Message response = client.messages().create(params);150      IO.println(response);151  }152  ```153154  ```php PHP155  $client = new Client();156157  $response = $client->messages->create(158      maxTokens: 2048,159      messages: [160          ['role' => 'user', 'content' => 'Open example.com/docs and tell me how to get started.'],161      ],162      model: 'claude-opus-5',163      tools: [164          ['type' => 'browser_toolset_20260801'],165      ],166  );167168  echo $response;169  ```170171  ```ruby Ruby172  client = Anthropic::Client.new173174  response = client.messages.create(175    model: "claude-opus-5",176    max_tokens: 2048,177    tools: [178      { type: "browser_toolset_20260801" }179    ],180    messages: [181      {182        role: "user",183        content: "Open example.com/docs and tell me how to get started."184      }185    ]186  )187188  puts response189  ```190</CodeGroup>191192Claude's first response ends with `stop_reason: "tool_use"` and carries one or more member `tool_use` blocks, each naming a member tool in `name` and carrying `"toolset_name": "browser"`:193194```json Output195{196  "id": "msg_01HCDu4XSTLzTAcodEQ58vDo",197  "type": "message",198  "role": "assistant",199  "model": "claude-opus-5",200  "content": [201    {202      "type": "text",203      "text": "I'll open the documentation and read the page to find the getting-started instructions."204    },205    {206      "type": "tool_use",207      "id": "toolu_01NRLabsLyVHZPKxbKvkfSMn",208      "name": "navigate",209      "toolset_name": "browser",210      "input": { "url": "https://example.com/docs" }211    },212    {213      "type": "tool_use",214      "id": "toolu_01UvHU5cDyTZ2vXKf5wCkPqR",215      "name": "read_page",216      "toolset_name": "browser",217      "input": { "filter": "interactive" }218    }219  ],220  "stop_reason": "tool_use",221  "stop_sequence": null222}223```224225Your executor (the part of your application that drives the browser and produces tool results) runs `navigate`, then `read_page`. Your application returns one `tool_result` per block in its next request, echoing `toolset_name` on each. The `navigate` result reports the tab it loaded in a `browser_state` block; the `read_page` result is text in which every element carries a reference:226227```json228{229  "role": "user",230  "content": [231    {232      "type": "tool_result",233      "tool_use_id": "toolu_01NRLabsLyVHZPKxbKvkfSMn",234      "toolset_name": "browser",235      "content": [236        { "type": "text", "text": "Navigated to https://example.com/docs" },237        {238          "type": "browser_state",239          "tabs": [240            {241              "tab_id": "tab-1",242              "title": "Documentation",243              "url": "https://example.com/docs",244              "active": true245            }246          ]247        }248      ]249    },250    {251      "type": "tool_result",252      "tool_use_id": "toolu_01UvHU5cDyTZ2vXKf5wCkPqR",253      "toolset_name": "browser",254      "content": [255        {256          "type": "text",257          "text": "link \"Documentation\" [ref_1]\nlink \"Getting started\" [ref_2]\ntextbox \"Search docs\" [ref_3]\nbutton \"Search\" [ref_4]\nlink \"Pricing\" [ref_5]"258        }259      ]260    }261  ]262}263```264265Claude now holds references it can act on, so its next turn can click `ref_2` to open the getting-started page, with no need to locate the link in a screenshot first.266267## How browser use works268269Browser use runs as an agent loop in your application: Claude returns member tool calls, your executor runs them against the browser, and you return the results until Claude answers in text.270271<Steps>272  <Step title="Provide Claude with the browser use tool and a user prompt" icon="tool">273    * Add the `browser_toolset_20260801` entry, and optionally other tools, to your API request.274    * Include a user prompt that calls for working with webpages, for example, "Open example.com/docs and tell me how to get started."275  </Step>276277  <Step title="Claude responds with member tool calls" icon="wrench">278    * Claude returns one or more `tool_use` blocks in a single assistant turn; several in one turn form a batch action, for example, `left_click`, then `type`, then `key`.279    * Each block's `name` is the member name, each carries `"toolset_name": "browser"`, and `input` holds only that member's parameters, with no `action` field. The response's `stop_reason` is `tool_use`.280  </Step>281282  <Step title="Run the calls in order and return results" icon="browser">283    * Iterate every `tool_use` block in `response.content` (don't assume there's exactly one) and run them sequentially, in the order they appear, because later calls usually depend on earlier ones.284    * Return one `tool_result` per block in a new `user` message, matched by `tool_use_id`, and echo `"toolset_name": "browser"` on each. Every call must be answered or the next request is rejected.285    * If a call fails, return `is_error: true` with a text description for that block, then apply the halt rule in [Batch actions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#batch-actions) to every later block in the turn.286  </Step>287288  <Step title="Claude continues until the task is complete" icon="arrows-clockwise">289    * Claude reads the results (page text, accessibility trees, screenshots, tab state) and, if it needs more, returns further member calls, which takes you back to step 3.290    * Otherwise, it returns a text response to the user.291  </Step>292</Steps>293294Here's a skeleton of that loop's tool-call step in two parts. First, stub member handlers stand in for your browser automation. Five members (`navigate`, `read_page`, `left_click`, `type`, and `screenshot`) return the text, or for `screenshot` the image block, that becomes the result content, and the dispatcher raises an error for any member it doesn't implement.295296<CodeGroup exclude="shell">297  ```python Python298  # Placeholder image data; a real executor captures the viewport and returns the PNG bytes299  PLACEHOLDER_PNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="300301302  def navigate(url):303      return f"navigated to {url}"304305306  def read_page():307      return 'link "Docs" [ref_1]\nbutton "Search" [ref_2]'308309310  def click(target):311      # A target is an element reference from read_page or find, or a viewport coordinate312      if target["type"] == "ref":313          return f"clicked {target['ref']}"314      return f"clicked at ({target['x']}, {target['y']})"315316317  def type_text(text):318      return f"typed: {text}"319320321  def capture_screenshot() -> list[ImageBlockParam]:322      # screenshot answers with an image block rather than text: return the result content list323      return [324          {325              "type": "image",326              "source": {"type": "base64", "media_type": "image/png", "data": PLACEHOLDER_PNG},327          }328      ]329330331  def handle_browser_action(name, tool_input):332      if name == "navigate":333          return navigate(tool_input["url"])334      elif name == "read_page":335          return read_page()336      elif name == "left_click":337          return click(tool_input["target"])338      elif name == "type":339          return type_text(tool_input["text"])340      elif name == "screenshot":341          return capture_screenshot()342      # Handle other actions as needed343      raise ValueError(f"Unknown or unimplemented member: {name}")344  ```345346  ```typescript TypeScript347  // Placeholder image data; a real executor captures the viewport as PNG bytes348  const PLACEHOLDER_PNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";349350  function navigate(url: string): string {351    return `navigated to ${url}`;352  }353354  function readPage(): string {355    return 'link "Docs" [ref_1]\nbutton "Search" [ref_2]';356  }357358  function clickElement(ref: string): string {359    return `clicked ${ref}`;360  }361362  function clickAt(x: number, y: number): string {363    return `clicked at (${x}, ${y})`;364  }365366  function typeText(text: string): string {367    return `typed: ${text}`;368  }369370  function captureScreenshot(): Anthropic.ImageBlockParam[] {371    // screenshot answers with an image block rather than text372    return [373      {374        type: "image",375        source: {376          type: "base64",377          media_type: "image/png",378          data: PLACEHOLDER_PNG,379        },380      },381    ];382  }383384  function handleBrowserAction(385    action: string,386    input: unknown,387  ): string | Anthropic.ImageBlockParam[] {388    const params: object =389      typeof input === "object" && input !== null ? input : {};390    if (action === "navigate" && "url" in params) {391      return navigate(String(params.url));392    } else if (action === "read_page") {393      return readPage();394    } else if (action === "left_click" && "target" in params) {395      // target is an element reference from read_page or a viewport coordinate396      const target: object =397        typeof params.target === "object" && params.target !== null398          ? params.target399          : {};400      if ("type" in target && target.type === "ref" && "ref" in target) {401        return clickElement(String(target.ref));402      } else if ("x" in target && "y" in target) {403        return clickAt(Number(target.x), Number(target.y));404      }405    } else if (action === "type" && "text" in params) {406      return typeText(String(params.text));407    } else if (action === "screenshot") {408      return captureScreenshot();409    }410    // Handle other actions as needed411    throw new Error(`Unknown or unimplemented member: ${action}`);412  }413  ```414415  ```csharp C#416  // Placeholder image data; a real executor captures the viewport and returns the PNG bytes417  const string PlaceholderPng = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";418419  string Navigate(string url) => $"navigated to {url}";420421  string ReadPage() =>422      """423      link "Docs" [ref_1]424      button "Search" [ref_2]425      """;426427  string ClickRef(string elementRef) => $"clicked {elementRef}";428429  string ClickAt(int x, int y) => $"clicked at ({x}, {y})";430431  // target is {"type": "ref", "ref": "ref_1"} or {"type": "coordinate", "x": 640, "y": 380}432  string Click(JsonElement target) =>433      target.GetProperty("type").GetString() == "ref"434          ? ClickRef(target.GetProperty("ref").GetString()!)435          : ClickAt(target.GetProperty("x").GetInt32(), target.GetProperty("y").GetInt32());436437  string TypeText(string text) => $"typed: {text}";438439  // screenshot answers with an image block rather than text: return the result content list440  List<Block> CaptureScreenshot() =>441      [442          new ImageBlockParam(443              new Base64ImageSource { Data = PlaceholderPng, MediaType = MediaType.ImagePng }444          ),445      ];446447  ToolResultBlockParamContent HandleBrowserAction(448      string action,449      IReadOnlyDictionary<string, JsonElement> input450  ) =>451      action switch452      {453          "navigate" => Navigate(input["url"].GetString()!),454          "read_page" => ReadPage(),455          "left_click" => Click(input["target"]),456          "type" => TypeText(input["text"].GetString()!),457          "screenshot" => CaptureScreenshot(),458          // Handle other actions as needed459          _ => throw new NotSupportedException($"Unknown or unimplemented member: {action}"),460      };461  ```462463  ```go Go464  // placeholderPNG stands in for a real capture: an executor returns the465  // viewport as base64-encoded PNG data.466  const placeholderPNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="467468  // textContent wraps text as tool_result content.469  func textContent(text string) []anthropic.ToolResultBlockParamContentUnion {470  	return []anthropic.ToolResultBlockParamContentUnion{471  		{OfText: &anthropic.TextBlockParam{Text: text}},472  	}473  }474475  func navigate(url string) string {476  	return fmt.Sprintf("navigated to %s", url)477  }478479  func readPage() string {480  	return "link \"Docs\" [ref_1]\nbutton \"Search\" [ref_2]"481  }482483  func clickRef(ref string) string {484  	return fmt.Sprintf("clicked %s", ref)485  }486487  func clickAt(x, y int) string {488  	return fmt.Sprintf("clicked at (%d, %d)", x, y)489  }490491  func typeText(text string) string {492  	return fmt.Sprintf("typed: %s", text)493  }494495  // captureScreenshot returns an image block rather than text.496  func captureScreenshot() []anthropic.ToolResultBlockParamContentUnion {497  	return []anthropic.ToolResultBlockParamContentUnion{{498  		OfImage: &anthropic.ImageBlockParam{499  			Source: anthropic.ImageBlockParamSourceUnion{500  				OfBase64: &anthropic.Base64ImageSourceParam{501  					MediaType: anthropic.Base64ImageSourceMediaTypeImagePNG,502  					Data:      placeholderPNG,503  				},504  			},505  		},506  	}}507  }508509  func handleBrowserAction(action string, params map[string]any) ([]anthropic.ToolResultBlockParamContentUnion, error) {510  	switch action {511  	case "navigate":512  		if url, ok := params["url"].(string); ok {513  			return textContent(navigate(url)), nil514  		}515  	case "read_page":516  		return textContent(readPage()), nil517  	case "left_click":518  		// target is either an element reference from read_page or a viewport coordinate519  		target, _ := params["target"].(map[string]any)520  		if ref, ok := target["ref"].(string); ok && target["type"] == "ref" {521  			return textContent(clickRef(ref)), nil522  		}523  		x, xok := target["x"].(float64)524  		y, yok := target["y"].(float64)525  		if xok && yok {526  			return textContent(clickAt(int(x), int(y))), nil527  		}528  	case "type":529  		if text, ok := params["text"].(string); ok {530  			return textContent(typeText(text)), nil531  		}532  	case "screenshot":533  		return captureScreenshot(), nil534  	// Handle other actions as needed535  	default:536  		return nil, fmt.Errorf("unknown or unimplemented member: %s", action)537  	}538  	// Reached when a member's input is missing a field or a field has the wrong type539  	return nil, fmt.Errorf("invalid input for %s", action)540  }541542  ```543544  ```java Java545  /** Placeholder pixels; a real executor captures the viewport and base64-encodes the PNG. */546  static final String PLACEHOLDER_PNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";547548  ToolResultBlockParam.Content captureScreenshot() {549      ImageBlockParam image = ImageBlockParam.builder()550              .source(Base64ImageSource.builder()551                      .mediaType(Base64ImageSource.MediaType.IMAGE_PNG)552                      .data(PLACEHOLDER_PNG)553                      .build())554              .build();555      return ToolResultBlockParam.Content.ofBlocks(556              List.of(ToolResultBlockParam.Content.Block.ofImage(image)));557  }558559  String navigate(String url) {560      return "navigated to " + url;561  }562563  String readPage() {564      return """565              link "Docs" [ref_1]566              button "Search" [ref_2]""";567  }568569  String clickRef(String ref) {570      return "clicked " + ref;571  }572573  String clickAt(long x, long y) {574      return "clicked at (" + x + ", " + y + ")";575  }576577  String typeText(String text) {578      return "typed: " + text;579  }580581  /** Runs one browser toolset member; {@code action} is the tool_use block's name. */582  ToolResultBlockParam.Content handleBrowserAction(String action, Map<String, JsonValue> input) {583      if (action.equals("screenshot")) {584          return captureScreenshot(); // the one member here that answers with an image block585      }586      String output = switch (action) {587          case "navigate" -> navigate(input.get("url").asStringOrThrow());588          case "read_page" -> readPage();589          case "left_click" -> {590              // target is {"type": "ref", "ref": "ref_1"} or {"type": "coordinate", "x": 640, "y": 380}591              Map<String, JsonValue> target =592                      (Map<String, JsonValue>) input.get("target").asObject().get();593              if (target.get("type").asStringOrThrow().equals("ref")) {594                  yield clickRef(target.get("ref").asStringOrThrow());595              }596              long x = ((Number) target.get("x").asNumber().get()).longValue();597              long y = ((Number) target.get("y").asNumber().get()).longValue();598              yield clickAt(x, y);599          }600          case "type" -> typeText(input.get("text").asStringOrThrow());601          // Handle other actions as needed602          default -> throw new UnsupportedOperationException("Unknown or unimplemented member: " + action);603      };604      return ToolResultBlockParam.Content.ofString(output);605  }606  ```607608  ```php PHP609  // Stand-in for real PNG bytes; a real executor captures the viewport610  const PLACEHOLDER_PNG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';611612  function navigateTo(string $url): string613  {614      return "navigated to {$url}";615  }616617  function readPage(): string618  {619      return <<<'TEXT'620          link "Docs" [ref_1]621          button "Search" [ref_2]622          TEXT;623  }624625  function clickTarget(array $target): string626  {627      // A target is an element reference from read_page or find, or a viewport pixel coordinate628      if ($target['type'] === 'ref') {629          return "clicked {$target['ref']}";630      }631632      return "clicked at ({$target['x']}, {$target['y']})";633  }634635  function typeText(string $text): string636  {637      return "typed: {$text}";638  }639640  function captureScreenshot(): array641  {642      // screenshot answers with an image block rather than text, so return the result content list643      $image = [644          'type' => 'image',645          'source' => ['type' => 'base64', 'media_type' => 'image/png', 'data' => PLACEHOLDER_PNG],646      ];647648      return [$image];649  }650651  function handleBrowserAction(string $name, array $input): string|array652  {653      return match ($name) {654          'navigate' => navigateTo($input['url']),655          'read_page' => readPage(),656          'left_click' => clickTarget($input['target']),657          'type' => typeText($input['text']),658          'screenshot' => captureScreenshot(),659          // Handle other actions as needed660          default => throw new RuntimeException("Unknown or unimplemented member: {$name}"),661      };662  }663  ```664665  ```ruby Ruby666  # Stand-in image data; a real executor captures the viewport as a PNG.667  PLACEHOLDER_PNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="668669  def navigate(url)670    "navigated to #{url}"671  end672673  def read_page674    <<~TREE675      link "Docs" [ref_1]676      button "Search" [ref_2]677    TREE678  end679680  def click(target)681    return "clicked #{target[:ref]}" if target[:type] == "ref"682683    "clicked at (#{target[:x]}, #{target[:y]})"684  end685686  def type_text(text)687    "typed: #{text}"688  end689690  def capture_screenshot691    [692      {693        type: "image",694        source: { type: "base64", media_type: "image/png", data: PLACEHOLDER_PNG }695      }696    ]697  end698699  def handle_browser_action(name, input)700    case name701    when "navigate"702      navigate(input[:url])703    when "read_page"704      read_page705    when "left_click"706      # target is an element reference (from read_page or find) or a coordinate707      click(input[:target])708    when "type"709      type_text(input[:text])710    when "screenshot"711      capture_screenshot712    # Handle other actions as needed713    else714      raise ArgumentError, "Unknown or unimplemented member: #{name}"715    end716  end717  ```718</CodeGroup>719720The second part runs a batch in order, dispatches each block to those handlers, echoes `toolset_name` on every result, and applies the halt rule from [Batch actions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#batch-actions), turning a handler error into an error result. The sampling loop that calls it is the one shown in [Understand the agent loop](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#understanding-the-agentic-loop), with the browser toolset in `tools`.721722<CodeGroup exclude="shell">723  ```python Python724  NOT_EXECUTED = "Not executed: an earlier action in this turn failed."725726727  def process_tool_calls(response: Message) -> list[ToolResultBlockParam]:728      """729      Run the browser actions in Claude's response in order and answer each730      one. After the first failure the rest are skipped, because Claude planned731      them assuming the earlier actions succeeded.732      """733      tool_results: list[ToolResultBlockParam] = []734      failed = False735      for block in response.content:736          # Only the browser toolset is declared; route other tools here if you add them737          if block.type != "tool_use" or block.toolset_name != "browser":738              continue739          result: ToolResultBlockParam = {740              "type": "tool_result",741              "tool_use_id": block.id,742              "toolset_name": "browser",743          }744          if failed:745              result["content"] = NOT_EXECUTED746              result["is_error"] = True747          else:748              try:749                  # A string or a list of content blocks; a real executor also adds a750                  # browser_state block to navigation and tab-management results751                  result["content"] = handle_browser_action(block.name, block.input)752              except Exception as err:753                  result["content"] = f"Error: {err}"754                  result["is_error"] = True755                  failed = True756          tool_results.append(result)757      return tool_results758  ```759760  ```typescript TypeScript761  const HALT_TEXT = "Not executed: an earlier action in this turn failed.";762763  function browserResult(764    toolUseId: string,765    content: string | Anthropic.ImageBlockParam[],766    isError?: boolean,767  ): Anthropic.ToolResultBlockParam {768    return {769      type: "tool_result",770      tool_use_id: toolUseId,771      toolset_name: "browser",772      content,773      is_error: isError,774    };775  }776777  function processToolCalls(778    response: Anthropic.Message,779  ): Anthropic.ToolResultBlockParam[] {780    const toolResults: Anthropic.ToolResultBlockParam[] = [];781    let failed = false;782    for (const block of response.content) {783      if (block.type !== "tool_use") {784        continue;785      }786      if (block.toolset_name !== "browser") {787        // This example declares only the browser toolset; route other tools788        // here if you add them.789        continue;790      }791      if (failed) {792        // A batch stops at its first failure; answer later actions unexecuted793        toolResults.push(browserResult(block.id, HALT_TEXT, true));794        continue;795      }796      try {797        // A string or an image block list; a real executor also adds a798        // browser_state block to navigation and tab-management results799        const result = handleBrowserAction(block.name, block.input);800        toolResults.push(browserResult(block.id, result));801      } catch (error) {802        failed = true;803        const message = error instanceof Error ? error.message : String(error);804        toolResults.push(browserResult(block.id, `Error: ${message}`, true));805      }806    }807    return toolResults;808  }809  ```810811  ```csharp C#812  const string HaltText = "Not executed: an earlier action in this turn failed.";813814  List<ContentBlockParam> ProcessToolCalls(Message response)815  {816      List<ContentBlockParam> toolResults = [];817      var failed = false;818      foreach (var block in response.Content)819      {820          if (!block.TryPickToolUse(out var toolUse))821          {822              continue;823          }824825          if (toolUse.ToolsetName != "browser")826          {827              // This example declares only the browser toolset; route other tools828              // here if you add them.829              continue;830          }831832          if (failed)833          {834              // A batch stops at its first failure; answer later actions without running them835              toolResults.Add(836                  new ToolResultBlockParam(toolUse.ID)837                  {838                      Content = HaltText,839                      IsError = true,840                      ToolsetName = "browser",841                  }842              );843              continue;844          }845846          try847          {848              // A string or a list of content blocks; a real executor also adds a849              // browser_state block to navigation and tab-management results850              var result = HandleBrowserAction(toolUse.Name, toolUse.Input);851              toolResults.Add(852                  new ToolResultBlockParam(toolUse.ID) { Content = result, ToolsetName = "browser" }853              );854          }855          catch (Exception e)856          {857              failed = true;858              toolResults.Add(859                  new ToolResultBlockParam(toolUse.ID)860                  {861                      Content = $"Error: {e.Message}",862                      IsError = true,863                      ToolsetName = "browser",864                  }865              );866          }867      }868      return toolResults;869  }870  ```871872  ```go Go873  const notExecuted = "Not executed: an earlier action in this turn failed."874875  // browserToolResult builds the result for one browser action. Unlike an876  // ordinary tool result, it must echo the toolset name. A real executor also877  // adds a browser_state block to navigation and tab-management results.878  func browserToolResult(toolUseID string, content []anthropic.ToolResultBlockParamContentUnion, isError bool) anthropic.ContentBlockParamUnion {879  	result := anthropic.ToolResultBlockParam{880  		ToolUseID:   toolUseID,881  		ToolsetName: anthropic.String("browser"),882  		Content:     content,883  	}884  	if isError {885  		result.IsError = anthropic.Bool(true)886  	}887  	return anthropic.ContentBlockParamUnion{OfToolResult: &result}888  }889890  // processToolCalls runs the browser actions in Claude's response in order and891  // builds one tool_result per tool_use block. After the first failure it skips892  // the rest: Claude planned them assuming the earlier actions succeeded.893  func processToolCalls(response *anthropic.Message) []anthropic.ContentBlockParamUnion {894  	var toolResults []anthropic.ContentBlockParamUnion895  	failed := false896  	for _, block := range response.Content {897  		switch variant := block.AsAny().(type) {898  		case anthropic.ToolUseBlock:899  			// This example declares only the browser toolset; route other tools here if you add them.900  			if variant.ToolsetName != "browser" {901  				continue902  			}903  			if failed {904  				toolResults = append(toolResults, browserToolResult(variant.ID, textContent(notExecuted), true))905  				continue906  			}907  			var input map[string]any908  			var content []anthropic.ToolResultBlockParamContentUnion909  			err := json.Unmarshal(variant.Input, &input)910  			if err == nil {911  				content, err = handleBrowserAction(variant.Name, input)912  			}913  			if err != nil {914  				failed = true915  				content = textContent("Error: " + err.Error())916  			}917  			toolResults = append(toolResults, browserToolResult(variant.ID, content, err != nil))918  		}919  	}920  	return toolResults921  }922923  ```924925  ```java Java926  /** The exact text the toolset contract prescribes for member calls skipped after a failure. */927  static final String HALT_TEXT = "Not executed: an earlier action in this turn failed.";928929  /** Every result answering a browser toolset member echoes toolset_name. */930  ToolResultBlockParam.Builder browserResult(ToolUseBlock toolUse) {931      return ToolResultBlockParam.builder()932              .toolUseId(toolUse.id())933              .toolsetName("browser");934  }935936  /**937   * Run the browser actions in Claude's response in order and build one938   * tool_result per tool_use block. After the first failure, skip the rest:939   * Claude planned them assuming the earlier actions succeeded.940   */941  List<ContentBlockParam> processToolCalls(Message response) {942      List<ContentBlockParam> toolResults = new ArrayList<>();943      boolean failed = false;944      for (ContentBlock block : response.content()) {945          // This example declares only the browser toolset; route other tools here if you add them.946          if (!block.isToolUse() || !block.asToolUse().toolsetName().equals(Optional.of("browser"))) {947              continue;948          }949          ToolUseBlock toolUse = block.asToolUse();950          ToolResultBlockParam result;951          if (failed) {952              result = browserResult(toolUse).content(HALT_TEXT).isError(true).build();953          } else {954              try {955                  Map<String, JsonValue> input =956                          (Map<String, JsonValue>) toolUse._input().asObject().get();957                  ToolResultBlockParam.Content output = handleBrowserAction(toolUse.name(), input);958                  // A real executor also adds a browser_state block to navigation and959                  // tab-management results; see "Track tabs with browser_state" on this page.960                  result = browserResult(toolUse).content(output).build();961              } catch (RuntimeException e) {962                  failed = true;963                  result = browserResult(toolUse).content("Error: " + e.getMessage()).isError(true).build();964              }965          }966          toolResults.add(ContentBlockParam.ofToolResult(result));967      }968      return toolResults;969  }970  ```971972  ```php PHP973  const HALT_TEXT = 'Not executed: an earlier action in this turn failed.';974975  function processToolCalls(Message $response): array976  {977      $toolResults = [];978      $failed = false;979      foreach ($response->content as $block) {980          // This example declares only the browser toolset; route other tools here if you add them.981          if (!($block instanceof \Anthropic\Messages\ToolUseBlock) || $block->toolsetName !== 'browser') {982              continue;983          }984          $result = ['type' => 'tool_result', 'tool_use_id' => $block->id, 'toolset_name' => 'browser'];985          if ($failed) {986              // A batch stops at its first failure; the remaining actions are answered without running987              $toolResults[] = [...$result, 'content' => HALT_TEXT, 'is_error' => true];988              continue;989          }990          try {991              // A real executor also returns a browser_state block on navigation and tab-management results992              $toolResults[] = [...$result, 'content' => handleBrowserAction($block->name, $block->input)];993          } catch (Throwable $e) {994              $failed = true;995              $toolResults[] = [...$result, 'content' => 'Error: ' . $e->getMessage(), 'is_error' => true];996          }997      }998999      return $toolResults;1000  }1001  ```10021003  ```ruby Ruby1004  NOT_EXECUTED = "Not executed: an earlier action in this turn failed."10051006  # Run the browser actions in Claude's response in order and build one1007  # tool_result per tool_use block. After the first failure, skip the rest:1008  # Claude planned them assuming the earlier actions succeeded.1009  def process_tool_calls(response)1010    tool_results = []1011    failed = false1012    response.content.each do |block|1013      # This example declares only the browser toolset; route other tools here1014      # if you add them.1015      next unless block.type == :tool_use && block.toolset_name == "browser"10161017      result = { type: "tool_result", tool_use_id: block.id, toolset_name: "browser" }1018      if failed1019        result.update(content: NOT_EXECUTED, is_error: true)1020      else1021        begin1022          # A String, or content blocks for a screenshot. A real executor also adds1023          # a browser_state block to navigation and tab-management results.1024          result[:content] = handle_browser_action(block.name, block.input)1025        rescue => e1026          result.update(content: "Error: #{e.message}", is_error: true)1027          failed = true1028        end1029      end1030      tool_results << result1031    end1032    tool_results1033  end1034  ```1035</CodeGroup>10361037Dispatch each block on the pair (`toolset_name`, `name`) rather than on `name` alone, because a custom tool in the same request may share a member's name; [Client toolsets](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference#client-toolsets) describes the parts of this contract both toolsets share. If Claude names a member your executor doesn't implement, or one you disabled, answer that block with an [error result](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#return-errors-from-your-executor) rather than dropping it.10381039When you stream the response, each member's `input` arrives as one complete `input_json_delta` rather than as fragments, so wait for the turn to finish before running the batch.10401041### Batch actions10421043A turn with several member calls is a batch action: run the calls in the order they appear, stop at the first failure, and answer every later call with `is_error: true` and the exact text `Not executed: an earlier action in this turn failed.` A batch uses the same response shape as [parallel tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use); the difference is that you run the blocks in order rather than concurrently. Here Claude clicks the search box it found earlier, types a query, and presses Enter in one turn:10441045```json1046{1047  "role": "assistant",1048  "content": [1049    {1050      "type": "tool_use",1051      "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",1052      "name": "left_click",1053      "toolset_name": "browser",1054      "input": { "target": { "type": "ref", "ref": "ref_3" } }1055    },1056    {1057      "type": "tool_use",1058      "id": "toolu_01Ez4kLb1nQ2vXo8sJ9pWm3c",1059      "name": "type",1060      "toolset_name": "browser",1061      "input": { "text": "install" }1062    },1063    {1064      "type": "tool_use",1065      "id": "toolu_01FkP8rTz6uYh2mNq4LsXw7v",1066      "name": "key",1067      "toolset_name": "browser",1068      "input": { "text": "Enter" }1069    }1070  ]1071}1072```10731074Your application returns three `tool_result` blocks in one `user` message, each carrying `toolset_name` and a short text acknowledgment such as `Clicked element ref_3.` Pressing Enter loads a results page, so the `key` result also carries a `browser_state` block with the tab's updated URL ([Tab context on other results](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#tab-context-on-other-results)). If the click had failed instead, its result would carry your error text and the other two results would carry the halt text, as shown under [Return errors from your executor](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#return-errors-from-your-executor).10751076You don't need to return a screenshot after every call. Claude typically ends a batch with an observation call (`screenshot`, `read_page`, or `get_page_text`), and your application can also attach its own observation, such as a fresh screenshot or accessibility tree, as an extra content block on the last result in the batch to save a round trip. Because a tab-management result must be exactly one `browser_state` block, attach it to the last result that isn't a tab-management call.10771078If your executor can run only one call per round trip, set `disable_parallel_tool_use` to `true` in `tool_choice` and Claude returns at most one member call per turn, at the cost of more round trips ([Disable parallel tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use#disable-parallel-tool-use)). The rest of the contract under [Batch actions for the computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#batch-actions) carries over, including one `tool_result` for every `tool_use` in the next `user` message, except for two things: the halt text and what a successful result's `content` holds. Result content follows [Member tools](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#member-tools) on this page instead: a `new_tab`, `switch_tab`, `close_tab`, or `list_tabs` result is exactly one `browser_state` block with no text or image ([Tab management results](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#tab-management-results)), and any other member's result may add a `browser_state` block to its text or image ([Tab context on other results](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#tab-context-on-other-results)). Where cache breakpoints inside a batch take effect is described in the `cache_control` row of the computer use tool's [Tool parameters](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#tool-parameters).10791080### Targets and coordinates10811082Member tools that act on a location take a `target` object, which is either a viewport-pixel coordinate or a reference to an element that `read_page` or `find` returned. The [Member tools](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#member-tools) tables write `Target` for a parameter that accepts either shape.10831084| Shape              | `target.type`  | Fields                                         | Accepted by                                                                                                                                                                               |1085| ------------------ | -------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1086| `CoordinateTarget` | `"coordinate"` | `x`, `y` (integers, viewport pixels)           | `left_click`, `right_click`, `middle_click`, `double_click`, `triple_click`, `hover`, `left_click_drag` (`from` and `target`), `left_mouse_down`, `left_mouse_up`, `mouse_move`, `scroll` |1087| `RefTarget`        | `"ref"`        | `ref` (an element reference such as `"ref_2"`) | `left_click`, `right_click`, `middle_click`, `double_click`, `triple_click`, `hover`, `scroll_to`, `form_input`, `file_upload`                                                            |10881089**Coordinates are viewport pixels**, the pixel space of a full-viewport `screenshot` with the origin at the top left of the rendered page; there's no surrounding desktop or window frame. The toolset declares no display dimensions and Claude infers the viewport size from the screenshots you return, so keep them one consistent size. A `zoom` doesn't change the frame, so its `region` and any coordinates Claude emits after seeing the zoomed image are still full-viewport pixels.10901091**Screenshots must fit the image limits.** The API doesn't downscale toolset images: a screenshot or zoom image over your model's [image size limits](https://platform.claude.com/docs/en/build-with-claude/vision#evaluate-image-size), or over the stricter per-image limit that applies once a request holds [more than 20 images](https://platform.claude.com/docs/en/build-with-claude/vision#request-limits), is rejected. Resize before returning, and scale Claude's coordinates back up by the inverse of your factor before dispatching them ([Size screenshots to fit image limits](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#handle-coordinate-scaling-for-higher-resolutions)).10921093**Element references come from `read_page` and `find`.** Each element in their output carries a tag such as `[ref_2]`, as in the Quick start result:10941095```text wrap1096link "Documentation" [ref_1]1097link "Getting started" [ref_2]1098textbox "Search docs" [ref_3]1099button "Search" [ref_4]1100link "Pricing" [ref_5]1101```11021103Claude passes a reference back as a `{"type": "ref", "ref": "ref_2"}` target on a later click, `hover`, `scroll_to`, `form_input`, or `file_upload` call, or as the `ref` parameter on `read_page` to read a subtree. Your executor assigns the references, keeps the mapping from each one to the underlying node (an accessibility-node ID, a stored selector, or equivalent), and acts on that node when a reference comes back.11041105References are scoped to the tab that produced them and stay valid until that tab navigates or its DOM changes materially. The API can't detect a stale or unknown reference, so when Claude passes a reference your executor no longer recognizes, return an error result such as `Error: ref_3 is stale or not found on the current page. Re-read the page to get fresh references.` Claude then reads the page again. Don't renumber references you've already handed out for a tab until it navigates, because that silently invalidates references Claude still holds.11061107Claude uses both targeting styles and switches between them based on what the page exposes; your prompt and what your executor returns steer the choice:11081109* **Prefer references where the page has a usable accessibility tree.** A reference survives layout shifts and reflows that make pixel coordinates fragile, and lets Claude act on controls that are hard to hit with a pointer.1110* **Fall back to coordinates for content the tree doesn't describe.** Canvas-rendered interfaces, embedded video or remote-desktop surfaces, heavily virtualized lists, and elements inside cross-origin iframes often have no useful node, so Claude works from `screenshot` and `zoom` and clicks by coordinate; your executor resolves which frame a coordinate lands in.1111* **Scope reads, and read the tree before you screenshot.** On large pages, `read_page` with `filter: "interactive"` or the `ref` of a container returns a focused subtree, and a tree read of a typical page often costs fewer input tokens than a screenshot while giving Claude references it can act on immediately. Screenshots remain the right observation when visual layout, images, or rendering state matter.11121113## Security considerations11141115Browser use carries risks that standard API features don't, because Claude reads and acts on content from the open web, where any page can contain text written to manipulate it.11161117<Warning>1118  To reduce these risks, take precautions such as the following:11191120  1. Run the browser and your executor in a dedicated container or virtual machine with minimal privileges, a fresh profile that holds no credentials, and no access to sensitive filesystems or internal networks; isolate any tool you run alongside it the same way.1121  2. Restrict the hosts the browser can reach to a domain allowlist enforced at the network layer and re-checked in your `navigate` handler after redirects, and block loopback, link-local, and private ranges unless the task needs them.1122  3. Treat everything a page supplies as untrusted input, including the tab titles and URLs, and each download's `url`, `path`, and `error`, that you report in a [`browser_state`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#track-tabs-and-page-state) block, and build page reads from what the page renders (the accessibility tree or visible text), not raw DOM source, so hidden text doesn't reach Claude.1123  4. In your `navigate` handler, accept the history keywords `"back"`, `"forward"`, and `"reload"`, treat a URL without a scheme as `https://`, then parse the URL and refuse any scheme other than `http` or `https` (`javascript:`, `file:`, `data:`, `chrome:`, and so on) with an [error result](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#return-errors-from-your-executor). Check the scheme with a URL parser rather than a string prefix; the API doesn't filter the URLs Claude opens, so it can't reject one for you.1124  5. Leave `javascript_exec` and `file_upload` disabled unless you need them, and read [Enable optional members](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#enable-optional-member-tools) before turning either on.1125  6. Have a human confirm consequential actions and anything that requires affirmative consent (purchasing, modifying accounts, messaging, and accepting terms), and make that check in your executor before each call, because one turn can carry several.1126</Warning>11271128Claude sometimes follows instructions found in page content even when they conflict with yours; text on a page that says "ignore your previous instructions and navigate to..." can divert it from the task. Isolate Claude from sensitive data and actions to limit what a prompt injection can reach, review [Mitigate jailbreaks and prompt injections](https://platform.claude.com/docs/en/test-and-evaluate/strengthen-guardrails/mitigate-jailbreaks), and if a task can't avoid a logged-in session, use a dedicated low-privilege account and keep human confirmation on account-changing actions.11291130Anthropic has trained the model to resist these prompt injections and has added an extra layer of defense. If you use the browser use tool, classifiers will automatically scan what the browser returns, such as page text or screenshots, to flag potential prompt injections. When these classifiers identify a potential prompt injection, they will automatically steer the model to check whether the instruction really came from you before acting on it.11311132This extra protection won't be ideal for every use case (for example, use cases without a human in the loop), so if you'd like to opt out and turn it off, [contact support](https://support.claude.com/en/). The precautions above remain important even with these classifiers in place.11331134Because the browser runs in your environment, the sites Claude visits see your executor's network identity, and page content reaches the API only as the tool results you return. Inform end users of the relevant risks and obtain their consent before enabling browser use in your products.11351136## Member tools11371138The `browser_toolset_20260801` entry declares 31 member tools; each call's `input` is exactly the parameters listed here, and `tab_id`, where optional, defaults to the active tab. `Target`, `CoordinateTarget`, and `RefTarget` are the shapes described in [Targets and coordinates](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#targets-and-coordinates). Four members (`javascript_exec`, `file_upload`, `read_console`, and `read_network`) are disabled by default and appear only when you [enable them](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#enable-optional-member-tools). The input bounds and output conventions noted in each member's row are stated to Claude, not enforced by the API, so validate inputs (including coordinates against your viewport) and apply the conventions in your executor.11391140Only `screenshot` and `zoom` require an [`image` block](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls#handling-results-from-client-tools) in their result, and the four tab-management members (`new_tab`, `list_tabs`, `switch_tab`, and `close_tab`) return exactly one `browser_state` block (see [Tab management results](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#tab-management-results)). Every other member returns a `text` block: either a short acknowledgment such as `Clicked element ref_2.` or the member's output. Any result other than a tab-management result may also carry an `image` block, typically a screenshot taken after the action, so Claude sees the outcome without a separate `screenshot` call; [Batch actions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#batch-actions) shows where to attach one in a batch. A member `tool_result` may contain only `text`, `image`, and `browser_state` content blocks.11411142### Navigation and capture11431144| Member       | Input               | Description                                                                                                                                                                                                                                                                                     |1145| ------------ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1146| `navigate`   | `url`, `tab_id?`    | Load an `http` or `https` URL, or move through history with `"back"`, `"forward"`, or `"reload"`. Treat a URL without a scheme as `https://` and refuse any other scheme with an error result. Return a short acknowledgment, plus a `browser_state` block when the tab's URL or title changed. |1147| `screenshot` | `tab_id?`           | Capture the viewport and return an `image` block.                                                                                                                                                                                                                                               |1148| `zoom`       | `region`, `tab_id?` | Return a cropped, upscaled `image` of `region`, given as `[x0, y0, x1, y1]` in viewport pixels, for closer inspection of small text or controls.                                                                                                                                                |11491150### Pointer11511152| Member            | Input                                                                       | Description                                                                                                                                                    |1153| ----------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |1154| `left_click`      | `target: Target`, `modifiers?`, `tab_id?`                                   | Left-click a coordinate or a referenced element. `modifiers` is a chord held during the click, for example, `"shift"` or `"ctrl+shift"`.                       |1155| `right_click`     | `target: Target`, `modifiers?`, `tab_id?`                                   | Right-click a coordinate or element.                                                                                                                           |1156| `middle_click`    | `target: Target`, `modifiers?`, `tab_id?`                                   | Middle-click a coordinate or element.                                                                                                                          |1157| `double_click`    | `target: Target`, `modifiers?`, `tab_id?`                                   | Double left-click a coordinate or element.                                                                                                                     |1158| `triple_click`    | `target: Target`, `modifiers?`, `tab_id?`                                   | Triple left-click a coordinate or element, which typically selects a line or paragraph.                                                                        |1159| `hover`           | `target: Target`, `tab_id?`                                                 | Move the pointer over a coordinate or element without clicking.                                                                                                |1160| `left_click_drag` | `from: CoordinateTarget`, `target: CoordinateTarget`, `tab_id?`             | Press at `from`, drag to `target`, and release.                                                                                                                |1161| `left_mouse_down` | `target: CoordinateTarget`, `tab_id?`                                       | Press and hold the left button at a coordinate; pair with `left_mouse_up` for a custom drag.                                                                   |1162| `left_mouse_up`   | `target: CoordinateTarget`, `tab_id?`                                       | Release the left button at a coordinate.                                                                                                                       |1163| `mouse_move`      | `target: CoordinateTarget`, `tab_id?`                                       | Move the pointer to a coordinate.                                                                                                                              |1164| `scroll`          | `target: CoordinateTarget`, `scroll_direction`, `scroll_amount?`, `tab_id?` | Scroll at a viewport position. `scroll_direction` is `"up"`, `"down"`, `"left"`, or `"right"`; `scroll_amount` is in scroll-wheel notches, 1 to 10, default 3. |1165| `scroll_to`       | `target: RefTarget`, `tab_id?`                                              | Scroll a referenced element into view.                                                                                                                         |11661167### Keyboard and timing11681169| Member     | Input                         | Description                                                                                                                                                                               |1170| ---------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1171| `type`     | `text`, `tab_id?`             | Type a literal string at the current focus.                                                                                                                                               |1172| `key`      | `text`, `repeat?`, `tab_id?`  | Press a key or chord. `text` is a single key (`"Enter"`), a chord joined with `+` (`"ctrl+a"`), or a space-separated sequence (`"Backspace Backspace"`); `repeat` is 1 to 100, default 1. |1173| `hold_key` | `text`, `duration`, `tab_id?` | Hold a key or chord for `duration` seconds, 0 to 30.                                                                                                                                      |1174| `wait`     | `duration`, `tab_id?`         | Pause for `duration` seconds, 0 to 30.                                                                                                                                                    |11751176### Page reading11771178| Member          | Input                                  | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |1179| --------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1180| `read_page`     | `filter?`, `depth?`, `ref?`, `tab_id?` | Return the page's accessibility tree as text with each element tagged with a reference such as `[ref_2]`. With `filter` omitted, return every visible element; with `"interactive"`, only visible interactive elements; with `"all"`, also elements outside the viewport. `depth` caps the tree depth (minimum 1, default 15) and `ref` scopes the read to that element's subtree. Cap the output at 50,000 characters and say so in the text; Claude then narrows with a smaller `depth` or a `ref`. |1181| `find`          | `query`, `tab_id?`                     | Search for elements matching a natural-language description such as `"search field"` or `"add to cart button"`, and return up to 20 matches in the same tagged format as `read_page`.                                                                                                                                                                                                                                                                                                                 |1182| `get_page_text` | `tab_id?`                              | Return the page's visible text as plain text, prioritizing the main article content; suited to articles, documentation, and other text-heavy pages.                                                                                                                                                                                                                                                                                                                                                   |11831184### Forms and files11851186| Member                              | Input                                                     | Description                                                                                                                                                                                                                                                                      |1187| ----------------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1188| `form_input`                        | `target: RefTarget`, `value`, `tab_id?`                   | Set a form element's value directly. `value` is a `string`, `number`, or `boolean`; use a `boolean` for checkboxes and an option's value or visible text for selects.                                                                                                            |1189| `file_upload` (disabled by default) | `target: RefTarget`, `paths?`, `document_ids?`, `tab_id?` | Set the files on a file-input element from `paths` on the executor's filesystem, `document_ids` your application has staged, or both; at least one is required. See [Upload files](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#upload-files). |11901191### Diagnostics and scripting11921193| Member                                  | Input             | Description                                                                                                                                                                                                                                                                      |1194| --------------------------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1195| `read_console` (disabled by default)    | `tab_id?`         | Return the tab's console entries (log, warning, and error lines) accumulated since the last read, one line per entry. See [Read console and network activity](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#read-console-and-network-activity). |1196| `read_network` (disabled by default)    | `tab_id?`         | Return the tab's network requests (method, URL, status, MIME type, timing) since the last read, one line per entry.                                                                                                                                                              |1197| `javascript_exec` (disabled by default) | `text`, `tab_id?` | Run `text` as JavaScript in the page context and return the value of the last expression as text. See [Enable optional members](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#enable-optional-member-tools).                                    |11981199### Tab management12001201| Member       | Input               | Description                            |1202| ------------ | ------------------- | -------------------------------------- |1203| `new_tab`    | (none)              | Open a tab and make it the active tab. |1204| `list_tabs`  | (none)              | Report the tab inventory.              |1205| `switch_tab` | `tab_id` (required) | Make `tab_id` the active tab.          |1206| `close_tab`  | `tab_id` (required) | Close `tab_id`.                        |12071208On success, each of these returns exactly one `browser_state` block and no text or image; see [Tab management results](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#tab-management-results).12091210## Configure the toolset12111212Besides `type`, the toolset entry accepts `configs`, `cache_control`, and `allowed_callers`; the rules these fields share with the computer use toolset are listed under [Client toolsets](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference#client-toolsets), and this section covers the browser-specific defaults. `configs` is an object keyed by member name, and each member's value accepts two fields:12131214| Field           | Default                                                                                                                                                             | Meaning                                                                                                                                                                                                                                                                                                                                          |1215| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |1216| `enabled`       | `true`, except `false` for the four [optional members](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#enable-optional-member-tools) | Whether the member is offered to Claude.                                                                                                                                                                                                                                                                                                         |1217| `defer_loading` | `false`                                                                                                                                                             | Whether the toolset's definition is deferred for tool search. Must resolve to the same value on every enabled member. With the four optional members left disabled, deferring the toolset means setting it on the other 27; see [Client toolsets](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference#client-toolsets). |12181219### Enable or disable member tools12201221List only the members you want to change in `configs`; every member you omit keeps its default. For example, an executor that implements console reads but not low-level pointer or key-hold control turns `read_console` on and withholds three members:12221223```json1224{1225  "type": "browser_toolset_20260801",1226  "configs": {1227    "read_console": { "enabled": true },1228    "left_mouse_down": { "enabled": false },1229    "left_mouse_up": { "enabled": false },1230    "hold_key": { "enabled": false }1231  }1232}1233```12341235A disabled member disappears from the definition Claude sees; that doesn't guarantee Claude never names it, so your executor still answers such a call with an [error result](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#return-errors-from-your-executor).12361237### Combine with other tools12381239Declare the browser use tool alongside your own tools and other Anthropic-provided tools in the same `tools` array. A custom tool may share a member's name (your own `navigate`, for example), because `toolset_name` distinguishes Claude's calls, but no other entry may be named `browser`, and a request may contain only one browser toolset entry.12401241You can also declare it alongside the [computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool), either the toolset or an earlier computer use tool version. The two work independently, each in its own coordinate frame (viewport pixels here, desktop screenshot pixels there), and Claude's calls to members that share a name, such as `screenshot` or `key`, are told apart by `toolset_name`.12421243## Enable optional members12441245Four member tools are disabled by default: `javascript_exec` and `file_upload` because they widen what a manipulated page could make Claude do, and `read_console` and `read_network` because not every browser automation stack can supply those logs and they widen what page-controlled content reaches Claude. Enable each one with `configs` (for example, `"configs": {"file_upload": {"enabled": true}}`) only when your executor implements it and the task needs it.12461247### Upload files12481249`file_upload` sets the files on an `<input type="file">` element directly, which is more reliable than driving a native file chooser. Its `target` is a reference only, because the call needs the element's identity, and it takes `paths`, `document_ids`, or both:12501251* `paths` are file paths on the executor's filesystem, for deployments where the executor can read your application's files directly (the same condition under which you populate a download's `path`).1252* `document_ids` are identifiers for files your application has staged for the browser, for deployments where it can't. Your application defines what the identifiers mean; scope their resolution the way you scope `paths`, to files staged for this task.12531254```json1255{1256  "type": "tool_use",1257  "id": "toolu_01N7gVzFEfZjLjgsYwnrPgrF",1258  "name": "file_upload",1259  "toolset_name": "browser",1260  "input": {1261    "target": { "type": "ref", "ref": "ref_12" },1262    "paths": ["/home/user/uploads/summary.pdf"],1263    "tab_id": "tab-2"1264  }1265}1266```12671268Claude writes these paths while it's reading untrusted pages, so an unrestricted implementation would let a malicious page direct the upload of any file the executor can read to a site the page controls. Enable the member only when your executor resolves each path (following symlinks and `..` segments) and accepts nothing outside a dedicated, allowlisted upload directory that holds only files meant for the task. Don't reuse the browser's download directory for this; if you do, every file a page causes the browser to download becomes uploadable.12691270### Run JavaScript in the page12711272`javascript_exec` runs the expression Claude writes in the page's context and returns the value of the last expression as text; Claude writes an expression, not a `return` statement. The code runs with the page's full privileges, including its cookies, storage, and same-origin requests. Enable the member only in sessions that hold no credentials, keep the domain allowlist from [Security considerations](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#security-considerations) in force, treat the returned value as untrusted input, and log the code Claude emits.12731274### Read console and network activity12751276`read_console` returns the tab's console entries and `read_network` returns its network requests, each as text with one line per entry accumulated since the previous read of that tab. A console line carries a log, warning, or error entry; a network line carries the method, URL, status, MIME type, and timing. Entries exist only from the moment your browser automation attached to the tab, so an empty result doesn't mean a tab that was already open had no traffic.12771278These members let Claude diagnose a misbehaving page (a failed request behind a spinner, a script error behind a dead button) without repeated screenshots. Console and network entries are page-controlled and often contain secrets such as tokens in request URLs, so redact credential-like values you don't want in Claude's context and truncate very long entries before returning them.12791280## Track tabs with `browser_state`12811282Claude addresses tabs by `tab_id`, your application is the source of truth for which tabs exist, and you report that state in a `browser_state` content block that Claude never sees directly: the API renders the text Claude reads from it.12831284```json1285{1286  "type": "browser_state",1287  "tabs": [1288    {1289      "tab_id": "tab-1",1290      "title": "Documentation",1291      "url": "https://example.com/docs",1292      "active": true1293    },1294    { "tab_id": "tab-2", "title": "Pricing", "url": "https://example.com/pricing" }1295  ]1296}1297```12981299* `tabs` is the full inventory of open tabs after the call, not a delta. It may be empty; whenever it isn't, exactly one entry carries `"active": true`.1300* `state_changes` (not shown here) reports side effects of the call: a `tab_opened` entry for each tab the call opened that's still open when it finishes, whose `tab_id` must also appear in `tabs`, and [download events](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#report-downloads). Omit the field when there's nothing to report; an empty array is rejected.1301* Send the block only on results that answer a browser member call, at most once per `tool_result`, and never on a result with `is_error: true`. You express "no tab state to report" by omitting the block.1302* The API renders `tabs`, and any download entries in `state_changes`, into text for Claude. The next two sections and [Report downloads](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#report-downloads) show that text.13031304**You assign `tab_id` values.** Any stable string works, such as your automation library's page identifier or your own counter, as long as you don't reuse a `tab_id` while a tab with that identifier is still listed as open in an earlier result. The API enforces these limits on the block:13051306* Each `tab_id`, `title`, and `url` may be at most 4,096 characters, `tab_id` must be non-empty, and none may contain control characters (including newlines) or Unicode line or paragraph separators.1307* A block may list at most 100 tabs and 200 state changes.1308* The same limits apply to the `tab_id` Claude passes to `switch_tab` and `close_tab`, because the API renders it into the result text, so answer a call whose `tab_id` violates them with an error result instead of a `browser_state` block.13091310<Warning>1311  Tab titles and URLs come from the page and render into text Claude reads, so they're a prompt-injection surface. The API renders tab URLs verbatim, so sanitize page-supplied URLs before populating `tabs`. It escapes double quotes and backslashes in titles when it renders them, so don't pre-escape titles (a pre-escaped title reaches Claude double-escaped); truncating or dropping suspicious titles is still worthwhile. A download entry's `url`, `path`, and `error` also render into text Claude reads, so treat them as untrusted too; the API quotes and escapes them as it does titles. The length and character limits the API enforces are a floor, not a defense.1312</Warning>13131314### Tab management results13151316For `new_tab`, `switch_tab`, `close_tab`, and `list_tabs`, a successful result's `content` is exactly one `browser_state` block with no text or image, and the API writes the text Claude sees. A `new_tab` result's block must also carry exactly one `tab_opened` state change whose `tab_id` matches the entry marked `active: true`.13171318| Member       | Text Claude sees                                                                                                            |1319| ------------ | --------------------------------------------------------------------------------------------------------------------------- |1320| `switch_tab` | `Switched to tab {tab_id}`, taken from the call's `input.tab_id`                                                            |1321| `close_tab`  | `Closed tab {tab_id}`, taken from the call's `input.tab_id`                                                                 |1322| `new_tab`    | `Created new tab with tab_id: {tab_id}, URL: {url}. It is now the current tab.`, taken from the entry marked `active: true` |1323| `list_tabs`  | `Available tabs:` followed by one line per tab, or `No tabs available` when `tabs` is empty                                 |13241325A `list_tabs` result whose block lists two tabs with the first one active renders as follows, with each line indented two spaces and `(current)` appended to the active tab only:13261327```text wrap1328Available tabs:1329  • tab_id tab-1: "Documentation" (https://example.com/docs) (current)1330  • tab_id tab-2: "Pricing" (https://example.com/pricing)1331```13321333An error result for one of these members is the reverse: ordinary error text in `content`, `is_error: true`, and no `browser_state` block.13341335For example, when Claude calls `new_tab` (its `input` is empty), your executor opens the tab, makes it active, and returns the inventory with one `tab_opened` entry:13361337```json1338{1339  "role": "user",1340  "content": [1341    {1342      "type": "tool_result",1343      "tool_use_id": "toolu_01WvHSbQVV9j5nWGvTmk4vNL",1344      "toolset_name": "browser",1345      "content": [1346        {1347          "type": "browser_state",1348          "tabs": [1349            { "tab_id": "tab-1", "title": "Documentation", "url": "https://example.com/docs" },1350            { "tab_id": "tab-2", "title": "Pricing", "url": "https://example.com/pricing" },1351            { "tab_id": "tab-3", "title": "", "url": "about:blank", "active": true }1352          ],1353          "state_changes": [{ "type": "tab_opened", "tab_id": "tab-3" }]1354        }1355      ]1356    }1357  ]1358}1359```13601361Claude sees `Created new tab with tab_id: tab-3, URL: about:blank. It is now the current tab.` Report the URL the tab was opened at, as here, not one it later redirects to; later results report the tab's then-current URL.13621363### Tab context on other results13641365On every other member the block is optional: send it when the set of open tabs, the active tab, or a tab's title or URL changed, or when there are `state_changes` to report, and always include the full `tabs` inventory. When a result carries both text and a `browser_state` block, the API appends a `Tab Context` footer to that result's text, separated from your text by a blank line, so Claude receives the new state without a separate `list_tabs` call:13661367```text wrap1368Tab Context:1369- Executed on tab_id: tab-11370- Available tabs:1371  • tab_id tab-1: "Documentation" (https://example.com/docs)1372  • tab_id tab-2: "Pricing" (https://example.com/pricing)1373```13741375`Executed on` names the tab the call ran on, which is its `tab_id` input when present and otherwise the active tab, and the footer's tab lines carry no `(current)` marker. Don't append this text yourself; send the structured block and let the API render it. The footer is deduplicated, so identical tab state isn't rendered again on later results and populating the block liberally costs nothing.13761377Three cases render no footer even when the block is present:13781379* Any `zoom` result.1380* A result with no `text` block (an image-only `screenshot` result, for example). Nothing is rendered or remembered for that result; the tab context appears on the next result that carries both text and a `browser_state` block, so include a short text block alongside the image when you want Claude to see a tab change on that same result. The exception is a result whose block reports a [download event](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#report-downloads). The API adds the download lines as a text block, and the footer follows them as it would on any result with text.1381* A result whose `tabs` list is empty on a call that carried no `tab_id`, because there's no tab to name.13821383For example, when Claude clicked the "Pricing" link (`ref_5`) earlier in this session, the page opened it in a new tab Claude didn't ask for, and without a report Claude would have to call `list_tabs` to discover it. Return the click's acknowledgment plus a block whose `state_changes` names the opened tab, marking whichever tab your executor left active:13841385```json1386{1387  "role": "user",1388  "content": [1389    {1390      "type": "tool_result",1391      "tool_use_id": "toolu_01EgTXj1FjE2FCTt2zNFWLao",1392      "toolset_name": "browser",1393      "content": [1394        { "type": "text", "text": "Clicked element ref_5." },1395        {1396          "type": "browser_state",1397          "tabs": [1398            {1399              "tab_id": "tab-1",1400              "title": "Documentation",1401              "url": "https://example.com/docs",1402              "active": true1403            },1404            { "tab_id": "tab-2", "title": "Pricing", "url": "https://example.com/pricing" }1405          ],1406          "state_changes": [{ "type": "tab_opened", "tab_id": "tab-2" }]1407        }1408      ]1409    }1410  ]1411}1412```14131414Claude sees `Clicked element ref_5.` followed by the Tab Context footer shown earlier. A tab opened during a call that failed gets no `tab_opened` entry, because error results carry no `browser_state`; it appears in the `tabs` inventory of the next successful result instead. In a batch, attach the block to the result of the call during which the change happened, and give every successful tab-management result its own block even when an earlier result in the same turn reported the same state.14151416### Report downloads14171418When a click or navigation starts a file download, report it in `state_changes` on the result of the call during which it happened, correlated across results by a `download_id` you assign. Downloads run asynchronously and can span several results, so there are three event types:14191420| `type`               | Fields                                       | When to send                                                                                                                                                                                                                                                                                                                                            |1421| -------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1422| `download_started`   | `download_id`, `url`                         | On the result of the call during which the download began. `url` is the final URL the file is served from, after redirects.                                                                                                                                                                                                                             |1423| `download_completed` | `download_id`, `url`, `path?`, `size_bytes?` | On the result of whichever later call is running when the download finishes. Include `path` only when another tool in the same environment (for example, the [bash tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/bash-tool) or `file_upload`) can read the file there; otherwise `download_id` is the download's only identifier. |1424| `download_failed`    | `download_id`, `url`, `error?`               | When the download fails or is canceled, with the reason in `error` if the browser provides one.                                                                                                                                                                                                                                                         |14251426The API renders each entry as one line of text for Claude, in the order the entries appear. It adds the lines after the result's text, separated by a blank line, and before any Tab Context footer. Every kind of member result carries the lines, including `zoom` and tab-management results. A result with no `text` block gets them as a text block of its own. Each line gives the `download_id` and `url`, plus `path` and `size_bytes` (for `download_completed`) or `error` (for `download_failed`) when you send them. You don't need to describe the download in your own text. The API wraps `url`, `path`, and `error` in double quotes and escapes double quotes and backslashes inside them, so don't pre-escape these values.14271428For example, a click on "Download price list (CSV)" (`ref_8`) in the Pricing tab starts a download, so the click's result carries a `download_started` entry with `download_id` `"dl-1"` and the file's URL. The download finishes while a later `screenshot` call is running, so that result's `content` holds the image, a text block such as `Screenshot captured.`, and this `browser_state` block reporting the completion under the same `download_id`:14291430```json1431{1432  "type": "browser_state",1433  "tabs": [1434    { "tab_id": "tab-1", "title": "Documentation", "url": "https://example.com/docs" },1435    {1436      "tab_id": "tab-2",1437      "title": "Pricing",1438      "url": "https://example.com/pricing",1439      "active": true1440    }1441  ],1442  "state_changes": [1443    {1444      "type": "download_completed",1445      "download_id": "dl-1",1446      "url": "https://example.com/pricing/price-list.csv",1447      "path": "/home/user/downloads/price-list.csv",1448      "size_bytes": 482131449    }1450  ]1451}1452```14531454Claude sees `Screenshot captured.` followed by a blank line and a line like this:14551456```text wrap1457Download completed with download_id: dl-1, URL: "https://example.com/pricing/price-list.csv". Saved to "/home/user/downloads/price-list.csv". Size: 48213 bytes.1458```14591460Download reports follow these rules:14611462* At most one entry per `download_id` in a single block, so a download that starts and finishes during the same call reports only `download_completed`.1463* Never send `state_changes` on an `is_error: true` result; report a download event that occurred during a failed call on the next successful result.1464* `state_changes` isn't an inventory of downloads in progress; report each event once.1465* Each entry carries only the fields its `type` declares. `size_bytes` is a non-negative integer, `download_id` is non-empty, and `download_id`, `url`, `path`, and `error` are each at most 4,096 characters with no control characters or Unicode line or paragraph separators. The `url` comes from the remote server and often carries signed query-string credentials after redirects, so strip query parameters you don't want in Claude's context and sanitize it before reporting it or using it in a filesystem path.14661467## Handle errors14681469Report a failed call to Claude as an ordinary error result: `is_error: true`, text content that says what went wrong, `toolset_name` echoed, and no `browser_state` block.14701471### Return errors from your executor14721473Make error text specific, because Claude reads it and adapts: `Error: Navigation to https://example.com/status timed out after 30 seconds. The page may be unavailable.` gives Claude something to act on where a bare `Error: navigation failed` doesn't. Other common cases:14741475<AccordionGroup>1476  <Accordion title="Refused navigation scheme">1477    ```json1478    {1479      "type": "tool_result",1480      "tool_use_id": "toolu_01LeUTyqkhRxBFq1QTG3pkwN",1481      "toolset_name": "browser",1482      "is_error": true,1483      "content": "Error: Navigation refused. Only http and https URLs are allowed."1484    }1485    ```1486  </Accordion>14871488  <Accordion title="Stale or unknown element reference">1489    ```json1490    {1491      "type": "tool_result",1492      "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",1493      "toolset_name": "browser",1494      "is_error": true,1495      "content": "Error: ref_3 is stale or not found on the current page. Re-read the page to get fresh references."1496    }1497    ```1498  </Accordion>14991500  <Accordion title="Disabled or unimplemented member">1501    ```json1502    {1503      "type": "tool_result",1504      "tool_use_id": "toolu_013h2Q55HcNwVyapSpy2s5ZG",1505      "toolset_name": "browser",1506      "is_error": true,1507      "content": "Error: javascript_exec is not enabled in this environment."1508    }1509    ```1510  </Accordion>15111512  <Accordion title="Skipped after an earlier failure in the turn">1513    When the `left_click` on `ref_3` from [Batch actions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#batch-actions) fails with the stale-reference error shown earlier, the `type` and `key` calls after it each get this result:15141515    ```json1516    {1517      "type": "tool_result",1518      "tool_use_id": "toolu_01FkP8rTz6uYh2mNq4LsXw7v",1519      "toolset_name": "browser",1520      "is_error": true,1521      "content": "Not executed: an earlier action in this turn failed."1522    }1523    ```1524  </Accordion>1525</AccordionGroup>15261527### Request errors15281529The API validates the toolset entry and every member `tool_use` and `tool_result` block in the conversation. When one is malformed, the API returns an `invalid_request_error` before Claude runs. In the following table, the left column names what you sent.15301531| Request                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Why it fails and what to do                                                                                                                                                                                                                                    |1532| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1533| An option or combination the toolset entry doesn't accept, for example, a `name`, `strict: true`, `input_examples`, `defer_loading` on the entry itself, a `configs` key that isn't a member name, a field other than `enabled` or `defer_loading` in a member's `configs` value ([Configure the toolset](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#configure-the-toolset)), enabled members whose `defer_loading` values differ ([Configure the toolset](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#configure-the-toolset)), a `configs` that leaves no member enabled, a code execution caller in `allowed_callers`, the legacy `fine-grained-tool-streaming-2025-05-14` beta header on the request, a `tool_choice` of type `tool` naming `browser` or a member, or a second browser toolset entry or another tool named `browser` | These aren't supported on client toolsets. See [Client toolsets](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference#client-toolsets) for each rule and its alternative.                                                              |1534| A `tool_result` answering a member call without `"toolset_name": "browser"` or with a different value, or `toolset_name` on a result whose call wasn't a member call                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | Echo `toolset_name` exactly on member results, and only on them.                                                                                                                                                                                               |1535| A member `tool_use` from an earlier turn with no matching `tool_result`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Answer every member call, including the ones you didn't run after a failure.                                                                                                                                                                                   |1536| A content block other than `text`, `image`, or `browser_state` in a member result                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | Member results accept only those three block types.                                                                                                                                                                                                            |1537| A `browser_state` block that breaks a rule in [Track tabs with `browser_state`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#track-tabs-and-page-state), for example, one on an `is_error: true` result or on a result that doesn't answer a browser member call, more than one in a result, a non-empty `tabs` without exactly one `active: true` entry, a duplicate `tab_id`, an empty `state_changes` array, a `tab_opened` whose `tab_id` isn't in `tabs`, two state changes for one `download_id` or a state-change field its `type` doesn't declare ([Report downloads](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#report-downloads)), or a field over its limits                                                                                                                                                                  | Fix the block. "Nothing to report" is expressed by omitting the block or the `state_changes` field, never by an empty value.                                                                                                                                   |1538| A successful `new_tab`, `switch_tab`, `close_tab`, or `list_tabs` result whose `content` isn't exactly one `browser_state` block, or a `new_tab` result without exactly one `tab_opened` matching the active tab                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | The API renders these results from the block and needs it in that exact shape; see [Tab management results](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#tab-management-results).                                            |1539| An `image` in a result over your model's [image size limits](https://platform.claude.com/docs/en/build-with-claude/vision#evaluate-image-size), or over the stricter per-image limit that applies once the request holds [more than 20 images](https://platform.claude.com/docs/en/build-with-claude/vision#request-limits), counting screenshots and `zoom` images in earlier results                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | The API doesn't downscale toolset images. Resize screenshots before returning them ([Size screenshots to fit image limits](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#handle-coordinate-scaling-for-higher-resolutions)). |1540| A `model` that doesn't support `browser_toolset_20260801`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | See [Compatibility](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#compatibility) for the supported models.                                                                                                                    |15411542## Limitations15431544* **Platform availability:** Browser use is available on the Claude API and [Google Cloud](https://platform.claude.com/docs/en/build-with-claude/claude-on-vertex-ai).1545* **Whole-input streaming only:** When you stream, each member's `input` arrives as one complete `input_json_delta` ([Client toolsets](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference#client-toolsets)).1546* **Element references are best-effort:** Highly dynamic pages (virtualized lists, canvas-rendered interfaces, pages that re-render on scroll) might not expose stable references, and Claude falls back to screenshots and coordinate clicks there.1547* **`read_console` and `read_network` depend on your browser automation:** They report only what it can capture, and only from the moment it attached to a tab.1548* **General agent limitations apply:** Latency, vision accuracy, and prompt-injection risks carry over from computer use (see the computer use tool's [Limitations](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#understand-computer-use-limitations)), and its guidance under [Optimize model performance with prompting](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#optimize-model-performance-with-prompting), [Manage screenshot history](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#manage-screenshot-history), and [Follow implementation best practices](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#follow-implementation-best-practices) (action delays, action validation, and logging) applies to browser executors too.15491550## Pricing and data retention15511552Browser use follows the standard [tool use pricing](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview#pricing). When using the browser use tool:15531554**Toolset definition overhead:** Declaring `browser_toolset_20260801` with its default members adds about 6,600 input tokens to a request (about 6,610 on Claude Fable 5, Claude Mythos 5, Claude Opus 5, and Claude Opus 4.8, and about 6,670 on Claude Sonnet 5), which covers the member tool definitions and the tool use system prompt. Enabling all four optional members adds about 880 tokens, and disabling members with `configs` reduces the count. The exact count for a request is reported in the response `usage`, and you can estimate it in advance with the [token counting endpoint](https://platform.claude.com/docs/en/build-with-claude/token-counting).15551556**Additional token consumption:**15571558* Screenshot and zoom images returned in tool results, billed as image input (see [Vision pricing](https://platform.claude.com/docs/en/build-with-claude/vision#evaluate-image-size))1559* Text tool results returned to Claude, such as accessibility trees, page text, and console or network entries15601561<Note>1562  If you also use the computer use tool, bash tool, text editor tool, or your own tools alongside browser use, those tools have their own token costs as documented on their respective pages.1563</Note>15641565The browser session, downloads, and uploaded files stay in your environment; the screenshots, page text, and tab state you return are part of your API request content and follow the standard retention policy, or your ZDR arrangement if you have one. The browser use tool is ZDR eligible; see [API and data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention) for retention periods and eligibility across features.15661567## Next steps15681569<CardGroup cols={3}>1570  <Card title="Computer use tool" icon="computer" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool">1571    Give Claude control of a full desktop when the task leaves the browser; its implementation guidance applies to browser executors too.1572  </Card>15731574  <Card title="Handle tool calls" icon="wrench" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls">1575    Format `tool_result` blocks, return images and errors, and continue the conversation.1576  </Card>15771578  <Card title="Tool reference" icon="book" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference">1579    Browse client toolsets and every other Anthropic-provided tool, with their versions and parameters.1580  </Card>1581</CardGroup>1582
Files main
Menu

Theme