> ## Documentation Index
> Fetch the complete documentation index at: https://hobbyist-e43fa225.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Automate browser tasks with Foundry agents

> Automate web browsing tasks with the Browser Automation tool in Microsoft Foundry agents. Create isolated Playwright sessions for navigation and form filling.

export const ZonePivot = ({group, options = [], defaultValue, label = "Choose an experience"}) => {
  const values = options.map(option => option.id);
  const optionKey = options.map(option => `${option.id}:${option.title}`).join("|");
  const [activePivot, setActivePivot] = useState(defaultValue || values[0]);
  const slugify = value => value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
  const resolvePivot = () => {
    if (typeof window === "undefined") return defaultValue || values[0];
    const params = new URLSearchParams(window.location.search);
    const requested = params.get("pivots");
    if (requested) {
      const requestedIds = requested.split(",").map(value => value.trim()).filter(Boolean);
      const match = requestedIds.find(id => values.includes(id));
      if (match) return match;
    }
    const hash = window.location.hash.replace(/^#/, "");
    if (hash) {
      const match = options.find(option => option.id === hash || slugify(option.title) === hash);
      if (match) return match.id;
    }
    try {
      const stored = window.localStorage.getItem(`foundry-zone-pivot:${group}`);
      if (values.includes(stored)) return stored;
    } catch {
      return defaultValue || values[0];
    }
    return defaultValue || values[0];
  };
  const publishPivotChange = value => {
    if (typeof window === "undefined") return;
    window.dispatchEvent(new CustomEvent("foundry-zone-pivot-change", {
      detail: {
        group,
        value
      }
    }));
  };
  const syncTableOfContents = () => {
    if (typeof window === "undefined") return;
    window.requestAnimationFrame(() => {
      const toc = document.getElementById("table-of-contents-content");
      if (!toc) return;
      const links = Array.from(toc.querySelectorAll('a[href^="#"]'));
      for (const link of links) {
        const item = link.closest("li");
        const rawId = link.getAttribute("href")?.slice(1);
        if (!item || !rawId) continue;
        let id = rawId;
        try {
          id = decodeURIComponent(rawId);
        } catch {}
        item.style.display = document.getElementById(id) ? "" : "none";
      }
    });
  };
  useEffect(() => {
    const resolvedPivot = resolvePivot();
    setActivePivot(resolvedPivot);
    publishPivotChange(resolvedPivot);
    window.setTimeout(syncTableOfContents, 0);
  }, [group, defaultValue, values.join("|"), optionKey]);
  const selectPivot = value => {
    setActivePivot(value);
    if (typeof window !== "undefined") {
      try {
        window.localStorage.setItem(`foundry-zone-pivot:${group}`, value);
      } catch {}
      const url = new URL(window.location.href);
      const current = url.searchParams.get("pivots");
      const preserved = current ? current.split(",").map(id => id.trim()).filter(id => id && !values.includes(id)) : [];
      url.searchParams.set("pivots", [...preserved, value].join(","));
      window.history.replaceState(null, "", `${url.pathname}${url.search}${url.hash}`);
    }
    publishPivotChange(value);
    window.setTimeout(syncTableOfContents, 0);
  };
  if (options.length < 2) return null;
  return <div className="not-prose my-6 border-b border-slate-200 pb-3 dark:border-slate-800">
      <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
        {label}
      </div>
      <div className="flex flex-wrap gap-2" role="tablist" aria-label={label}>
        {options.map(option => {
    const selected = option.id === activePivot;
    return <button key={option.id} type="button" role="tab" aria-selected={selected} onClick={() => selectPivot(option.id)} className={`rounded-md border px-3 py-1.5 text-sm font-medium transition ${selected ? "border-slate-900 bg-slate-900 text-white shadow-sm dark:border-slate-100 dark:bg-slate-100 dark:text-slate-950" : "border-slate-200 bg-white text-slate-700 hover:border-slate-400 hover:text-slate-950 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-200 dark:hover:border-slate-500"}`}>
              {option.title}
            </button>;
  })}
      </div>
    </div>;
};

export const ZoneContent = ({group, value, options = [], values = [], defaultValue, children}) => {
  const optionKey = options.map(option => `${option.id}:${option.title}`).join("|");
  const [activePivot, setActivePivot] = useState(defaultValue || values[0]);
  const slugify = value => value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
  const resolvePivot = () => {
    if (typeof window === "undefined") return defaultValue || values[0];
    const params = new URLSearchParams(window.location.search);
    const requested = params.get("pivots");
    if (requested) {
      const requestedIds = requested.split(",").map(value => value.trim()).filter(Boolean);
      const match = requestedIds.find(id => values.includes(id));
      if (match) return match;
    }
    const hash = window.location.hash.replace(/^#/, "");
    if (hash) {
      const match = options.find(option => option.id === hash || slugify(option.title) === hash);
      if (match) return match.id;
    }
    try {
      const stored = window.localStorage.getItem(`foundry-zone-pivot:${group}`);
      if (values.includes(stored)) return stored;
    } catch {
      return defaultValue || values[0];
    }
    return defaultValue || values[0];
  };
  useEffect(() => {
    setActivePivot(resolvePivot());
  }, [group, defaultValue, values.join("|"), optionKey]);
  useEffect(() => {
    const onPivotChange = event => {
      if (event.detail?.group === group && values.includes(event.detail.value)) {
        setActivePivot(event.detail.value);
      }
    };
    window.addEventListener("foundry-zone-pivot-change", onPivotChange);
    return () => window.removeEventListener("foundry-zone-pivot-change", onPivotChange);
  }, [group, values.join("|")]);
  if (activePivot !== value) return null;
  return <>{children}</>;
};

<Info>
  Items marked (preview) in this article are currently in public preview. This preview is provided without a service-level agreement, and we don't recommend it for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see [Supplemental Terms of Use for Microsoft Azure Previews](https://azure.microsoft.com/support/legal/preview-supplemental-terms/).
</Info>

This article explains how to configure and use the Browser Automation tool with Foundry agents to automate web browsing workflows.

<Warning>
  The Browser Automation Tool comes with significant security risks. When you use the Browser Automation Tool, an AI spins up remote browsers sessions to perform actions and can use credentials you explicitly share with the agent, such as to email, financial accounts, social networks, and enterprise systems. The AI agent may make mistakes and may be fooled by malicious data it may encounter on the Internet.

  You're responsible for reviewing and testing your applications and implementing your own responsible AI mitigations. By using the Browser Automation Tool, you are acknowledging that you bear responsibility and liability for any use of it and all outcomes. Use judgment in deciding which credentials you provide to your browser sessions. See the [Foundry Agent Service transparency note](https://learn.microsoft.com/azure/foundry/responsible-ai/agents/transparency-note).
</Warning>

Browser Automation Tool (BAT) enables scalable, reliable browser-based automation within Foundry agents. BAT is available as an MCP tool powered by Playwright workspaces as its headless browser infrastructure layer. It integrates seamlessly with modern agentic workflows while providing enterprise-grade security, observability, and extensibility.

Browser Automation Tool (BAT) provides a comprehensive platform for browser automation through:

* [Playwright Workspaces](https://aka.ms/pww/docs) (a Generally Available service) as the infrastructure layer
* Real-time debugging with Live View
* Take control for human-in-the-loop scenarios
* Support for private website browsing (Private preview)
* Built-in observability for reliability and optimization
* Flexible orchestration layers

<Note>
  The private website feature in Playwright Workspaces is currently available in private preview.
  Interested users can fill out this [form](https://aka.ms/pww/private-website-enrolment-form) to enroll for the private preview.
</Note>

### Usage support

The following table shows SDK and setup support.

| Microsoft Foundry support | Python SDK | C# SDK | JavaScript SDK | Java SDK | REST API | Basic agent setup | Standard agent setup |
| ------------------------- | ---------- | ------ | -------------- | -------- | -------- | ----------------- | -------------------- |
| ✔️                        | ✔️         | ✔️     | ✔️             | ✔️       | ✔️       | ✔️                | ✔️                   |

## How it works

The interaction starts when the user sends a query to an agent connected to the Browser Automation tool. For example, *"Show me all available yoga classes this week from the following URL \<url>."* When the agent receives the request, Foundry Agent Service creates an isolated browser session using your provisioned Playwright workspace. Each session is sandboxed for privacy and security.

The browser performs Playwright-driven actions, such as navigating to relevant pages and applying filters or parameters based on user preferences (such as time, location, and instructor). By combining the model with Playwright, the model can parse HTML or XML into DOM documents, make decisions, and perform actions like selecting UI elements, typing, and navigating websites. Exercise caution when using this tool.

An example flow is:

1. A user sends a request to the model that includes a call to the Browser Automation tool with the URL you want to go to.
2. The Browser Automation tool receives a response from the model. If the response has action items, those items contain suggested actions to make progress toward the specified goal. For example, an action might be a screenshot so the model can assess the current state with an updated screenshot or click with X/Y coordinates indicating where the mouse should be moved.
3. The Browser Automation tool executes the action in a sandboxed environment.
4. After executing the action, the Browser Automation tool captures the updated state of the environment as a screenshot.
5. The tool sends a new request with the updated state, and repeats this loop until the model stops requesting actions or the user decides to stop.

   The Browser Automation tool supports multi-turn conversations, allowing the user to refine their request and complete form filling and web scraping scenarios.

## Prerequisites

Before you begin, make sure you have:

* An Azure subscription. [Create one for free](https://azure.microsoft.com/pricing/purchase-options/azure-account?cid=msft_learn).
* Contributor or Owner role on a resource group.
* A Foundry project with a configured endpoint.
* An AI model deployed in your project (for example, `gpt-5.4`).
* A Playwright workspace resource.
* A project connection set up for your Playwright workspace.

### SDK requirements

For Python examples, install the required packages:

```bash theme={null}
pip install "azure-ai-projects>=2.0.0"
```

The .NET SDK is currently in preview. For more information, see the [quickstart](/get-started/get-started-code).

### Configuration

**Get your project endpoint**: Open your project in the [Foundry portal](https://ai.azure.com), and copy the endpoint from the project overview page. The format is `https://{account-name}.services.ai.azure.com/api/projects/{project-name}`.

**Connection ID format**: Use `/subscriptions/{{subscriptionID}}/resourceGroups/{{resourceGroupName}}/providers/Microsoft.CognitiveServices/accounts/{{foundryAccountName}}/projects/{{foundryProjectName}}/connections/{{foundryConnectionName}}`. You can find this value on the tool's details page after you connect the Browser Automation tool.

## Set up Browser Automation

### Step 1: Create a Playwright workspace

1. In the [Azure portal](https://portal.azure.com), create a [Playwright Workspace](https://aka.ms/pww/docs/manage-workspaces) resource.
2. After the workspace is created, go to **Settings** > **Access Management**.
3. Confirm the **Playwright Service Access Token** authentication method is enabled.
4. Select **Generate Token**, enter a name (for example, `foundry-connection`), and choose an expiry period.
5. **Copy the token immediately**. You can't view it again after closing the page.
6. On the workspace **Overview** page, copy the **Browser endpoint** (it starts with `wss://`).
7. Give the project identity a Contributor role on the Playwright workspace resource, or [configure a custom role](https://aka.ms/pww/docs/manage-workspace-access).

### Step 2: Connect the Browser Automation tool in Foundry

1. Go to the [Foundry portal](https://ai.azure.com/nextgen) and select your project.
2. Select **Build** > **Tools**.
3. Select **Create a toolbox**.
4. Fill in the **Name** and **Description** for your toolbox.
5. Under **Tools**, click on **Add**
6. Select **Browser Automation** and click **Add tool**
7. Enter the required fields
   * **Connection name**: Unique name for your connection
   * **Playwright Workspace**: Select the Playwright Workspace resource.
   * **Auth Type**: Select the authentication type for your connection.
8. Select **Connect**.
9. Click on **Publish** to save the toolbox

After the toolbox is created, you can view the **Project connection ID** on the tool's details page. Use this value as the browser automation connection ID in your code.

## Code example

After you run a sample, verify the tool was called by using tracing in Microsoft Foundry. For guidance on validating tool invocation, see [Best practices for using tools in Microsoft Foundry Agent Service](/agents/tool-best-practice). If you use streaming, you can also look for `browser_automation_preview_call` events.

<Note>
  * The .NET SDK is currently in preview. For more information, see the [quickstart](/get-started/get-started-code).
  * This article assumes you already created the Playwright workspace connection. See the prerequisites section.
</Note>

<ZonePivot group="csharp__java__python__rest__typescript" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}, {"id": "rest", "title": "REST"}, {"id": "typescript", "title": "TypeScript"}, {"id": "java", "title": "Java"}]} defaultValue="python" />

<ZoneContent group="csharp__java__python__rest__typescript" value="python" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}, {"id": "rest", "title": "REST"}, {"id": "typescript", "title": "TypeScript"}, {"id": "java", "title": "Java"}]} values={["python", "csharp", "rest", "typescript", "java"]} defaultValue="python">
  ## Use BrowserAutomationPreviewTool with agents example

  The following Python example demonstrates how to create an AI agent with browser automation capabilities. Select **Prompt Agents** to use the Azure AI Projects SDK to create a server-side prompt agent, or **Hosted Agents** to use the Agent Framework [`FoundryChatClient`](/agents/responses-api) to build an ephemeral, in-process agent.

  <Tabs>
    <Tab title="Prompt Agents">
      ```python theme={null}
      import json
      from azure.identity import DefaultAzureCredential
      from azure.ai.projects import AIProjectClient
      from azure.ai.projects.models import (
          PromptAgentDefinition,
          BrowserAutomationPreviewTool,
          BrowserAutomationToolParameters,
          BrowserAutomationToolConnectionParameters,
      )

      # Format: "https://resource_name.ai.azure.com/api/projects/project_name"
      PROJECT_ENDPOINT = "your_project_endpoint"
      BROWSER_CONNECTION_ID = "your-browser-automation-connection-id"

      # Create clients to call Foundry API
      project = AIProjectClient(
          endpoint=PROJECT_ENDPOINT,
          credential=DefaultAzureCredential(),
      )
      openai = project.get_openai_client()

      tool = BrowserAutomationPreviewTool(
          browser_automation_preview=BrowserAutomationToolParameters(
              connection=BrowserAutomationToolConnectionParameters(
                  project_connection_id=BROWSER_CONNECTION_ID,
              )
          )
      )

      agent = project.agents.create_version(
          agent_name="MyAgent",
          definition=PromptAgentDefinition(
              model="gpt-4.1-mini",
              instructions="""You are an Agent helping with browser automation tasks. 
              You can answer questions, provide information, and assist with various tasks 
              related to web browsing using the Browser Automation tool available to you.""",
              tools=[tool],
          ),
      )
      print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})")

      stream_response = openai.responses.create(
          stream=True,
          tool_choice="required",
          input="""
              Your goal is to report the percent of Microsoft year-to-date stock price change.
              To do that, go to the website finance.yahoo.com.
              At the top of the page, you will find a search bar.
              Enter the value 'MSFT', to get information about the Microsoft stock price.
              At the top of the resulting page you will see a default chart of Microsoft stock price.
              Click on 'YTD' at the top of that chart, and report the percent value that shows up just below it.""",
          extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}},
      )

      for event in stream_response:
          if event.type == "response.created":
              print(f"Follow-up response created with ID: {event.response.id}")
          elif event.type == "response.output_text.delta":
              print(f"Delta: {event.delta}")
          elif event.type == "response.text.done":
              print(f"\nFollow-up response done!")
          elif event.type == "response.output_item.done":
              item = event.item
              if item.type == "browser_automation_preview_call":
                  arguments_str = getattr(item, "arguments", "{}")

                  # Parse the arguments string into a dictionary
                  arguments = json.loads(arguments_str)
                  query = arguments.get("query")

                  print(f"Call ID: {getattr(item, 'call_id')}")
                  print(f"Query arguments: {query}")
          elif event.type == "response.completed":
              print(f"\nFollow-up completed!")
              print(f"Full response: {event.response.output_text}")

      print("\nCleaning up...")
      project.agents.delete_version(agent_name=agent.name, agent_version=agent.version)
      print("Agent deleted")
      ```

      ### What this code does

      This example creates an agent version with the Browser Automation tool enabled, then sends a prompt that requires the agent to use the tool. It also processes streaming events so you can observe progress and tool calls.

      ### Required inputs

      * A Foundry project endpoint and a browser automation connection ID. See [Configuration](#configuration) for details.

      ### Expected output

      When you create the agent, you see output similar to:

      ```console theme={null}
      Agent created (id: ..., name: ..., version: ...)
      ```

      During streaming, you might also see deltas and tool-call details. Output varies based on the website content and model behavior.
    </Tab>

    <Tab title="Hosted Agents">
      This sample uses [`FoundryChatClient`](/agents/responses-api) from the Microsoft Agent Framework and calls `get_browser_automation_tool()` to attach a Playwright connection. Install the package with `pip install agent-framework-foundry aiohttp`, set the `FOUNDRY_PROJECT_ENDPOINT`, `FOUNDRY_MODEL`, and `BROWSER_CONNECTION_ID` environment variables, and sign in with `az login`.

      ```python theme={null}
      import asyncio
      import os

      from agent_framework import Agent
      from agent_framework.foundry import FoundryChatClient
      from azure.identity import AzureCliCredential

      BROWSER_CONNECTION_ID = os.environ["BROWSER_CONNECTION_ID"]

      async def main() -> None:
          agent = Agent(
              client=FoundryChatClient(credential=AzureCliCredential()),
              instructions=(
                  "You help with browser automation tasks. Use the Browser Automation tool "
                  "to navigate and read information from websites."
              ),
              tools=[FoundryChatClient.get_browser_automation_tool(connection_id=BROWSER_CONNECTION_ID)],
          )

          result = await agent.run(
              "Go to finance.yahoo.com, search for MSFT, click 'YTD' on the price chart, "
              "and report the year-to-date percent change."
          )
          print(f"Agent: {result.text}")

      if __name__ == "__main__":
          asyncio.run(main())
      ```

      ### Expected output

      The agent navigates the live website through the Playwright connection and reports the YTD value it observes. Output varies based on website content:

      ```console theme={null}
      Agent: The year-to-date change for MSFT is approximately +18.4%.
      ```

      For more about Agent Framework Foundry tool factories, see the [Foundry provider samples](https://github.com/microsoft/agent-framework/tree/main/python/samples/02-agents/providers/foundry).
    </Tab>
  </Tabs>
</ZoneContent>

<ZoneContent group="csharp__java__python__rest__typescript" value="csharp" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}, {"id": "rest", "title": "REST"}, {"id": "typescript", "title": "TypeScript"}, {"id": "java", "title": "Java"}]} values={["python", "csharp", "rest", "typescript", "java"]} defaultValue="python">
  ## Use BrowserAutomationPreviewTool with agents example

  Before running this sample, complete the setup steps in [Set up Browser Automation](#set-up-browser-automation).

  The following C# example demonstrates how to create an AI agent with Browser Automation capabilities by using the `BrowserAutomationPreviewTool` and synchronous Azure AI Projects client. The agent can navigate to websites, interact with web elements, and perform tasks such as searching for stock prices. The example uses synchronous programming model for simplicity. For an asynchronous version, see the [Sample for use of BrowserAutomationPreviewTool and Agents](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/ai/Azure.AI.Extensions.OpenAI/samples/Sample23_BrowserAutomationTool.md) sample in the Azure SDK for .NET repository on GitHub.

  ```csharp theme={null}
  using System;
  using Azure.AI.Projects;
  using Azure.AI.Extensions.OpenAI;
  using Azure.Identity;

  // Format: "https://resource_name.ai.azure.com/api/projects/project_name"
  var projectEndpoint = "your_project_endpoint";
  var browserConnectionId = "your-browser-automation-connection-id";

  // Note that Browser automation operations can take longer than usual
  // and require the request timeout to be at least 5 minutes.
  AIProjectClientOptions options = new()
  {
      NetworkTimeout = TimeSpan.FromMinutes(5)
  };
  AIProjectClient projectClient = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential(), options: options);

  // Create the Browser Automation tool using the Playwright connection.
  BrowserAutomationPreviewTool playwrightTool = new(
      new BrowserAutomationToolParameters(
      new BrowserAutomationToolConnectionParameters(browserConnectionId)
      ));

  // Create the Agent version with the Browser Automation tool.
  DeclarativeAgentDefinition agentDefinition = new(model: "gpt-4.1-mini")
  {
      Instructions = "You are an Agent helping with browser automation tasks.\n" +
      "You can answer questions, provide information, and assist with various tasks\n" +
      "related to web browsing using the Browser Automation tool available to you.",
      Tools = { playwrightTool }
  };
  AgentVersion agentVersion = projectClient.AgentAdministrationClient.CreateAgentVersion(
      agentName: "myAgent",
      options: new(agentDefinition));

  // Create the response stream. Also set ToolChoice = ResponseToolChoice.CreateRequiredChoice()
  // on the ResponseCreationOptions to ensure the agent uses the Browser Automation tool.
  ProjectResponsesClient responseClient = projectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(agentVersion.Name);
  CreateResponseOptions responseOptions = new()
  {
      ToolChoice = ResponseToolChoice.CreateRequiredChoice(),
      StreamingEnabled = true,
      InputItems =
      {
          ResponseItem.CreateUserMessageItem("Your goal is to report the percent of Microsoft year-to-date stock price change.\n" +
              "To do that, go to the website finance.yahoo.com.\n" +
              "At the top of the page, you will find a search bar.\n" +
              "Enter the value 'MSFT', to get information about the Microsoft stock price.\n" +
              "At the top of the resulting page you will see a default chart of Microsoft stock price.\n" +
              "Click on 'YTD' at the top of that chart, and report the percent value that shows up just below it.")
      }
  };
  foreach (StreamingResponseUpdate update in responseClient.CreateResponseStreaming(options: responseOptions))
  {
      if (update is StreamingResponseCreatedUpdate createUpdate)
      {
          Console.WriteLine($"Stream response created with ID: {createUpdate.Response.Id}");
      }
      else if (update is StreamingResponseOutputTextDeltaUpdate textDelta)
      {
          Console.WriteLine($"Delta: {textDelta.Delta}");
      }
      else if (update is StreamingResponseOutputTextDoneUpdate textDoneUpdate)
      {
          Console.WriteLine($"Response done with full message: {textDoneUpdate.Text}");
      }
      else if (update is StreamingResponseErrorUpdate errorUpdate)
      {
          throw new InvalidOperationException($"The stream has failed with the error: {errorUpdate.Message}");
      }
  }

  // Delete the Agent version to clean up resources.
  projectClient.AgentAdministrationClient.DeleteAgentVersion(agentName: agentVersion.Name, agentVersion: agentVersion.Version);
  ```

  ### What this code does

  This example creates an agent version with the Browser Automation tool enabled, sends a prompt that requires tool usage, and prints streaming updates as the agent works through the browser steps.

  ### Required inputs

  * A Foundry project endpoint and a browser automation connection ID. See [Configuration](#configuration) for details.
  * A Playwright connection created in your Foundry project.

  ### Expected output

  You see streaming progress messages, such as text deltas, and a completed response. The output varies based on the website content and model behavior.
</ZoneContent>

<ZoneContent group="csharp__java__python__rest__typescript" value="rest" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}, {"id": "rest", "title": "REST"}, {"id": "typescript", "title": "TypeScript"}, {"id": "java", "title": "Java"}]} values={["python", "csharp", "rest", "typescript", "java"]} defaultValue="python">
  Get an access token:

  ```bash theme={null}
  export AGENT_TOKEN=$(az account get-access-token --scope "https://ai.azure.com/.default" --query accessToken -o tsv)
  ```

  The following cURL sample demonstrates how to create an agent with Browser Automation tool and perform web browsing tasks using REST API.

  ```bash theme={null}
  curl --request POST \
    --url "${FOUNDRY_PROJECT_ENDPOINT}/openai/v1/responses" \
    --header "Authorization: Bearer ${AGENT_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "User-Agent: insomnia/11.6.1" \
    --data @- <<JSON
  {
    "model": "${FOUNDRY_MODEL_DEPLOYMENT_NAME}",
    "input": [
      {
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "Your goal is to report the percent of Microsoft year-to-date stock price change."
          },
          {
            "type": "input_text",
            "text": "Go to finance.yahoo.com, search for MSFT, select YTD on the chart, and report the percent value shown."
          }
        ]
      }
    ],
    "tools": [
      {
        "type": "browser_automation_preview",
        "browser_automation_preview": {
          "connection": {
            "project_connection_id": "${BROWSER_AUTOMATION_PROJECT_CONNECTION_ID}"
          }
        }
      }
    ]
  }
  JSON
  ```
</ZoneContent>

<ZoneContent group="csharp__java__python__rest__typescript" value="typescript" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}, {"id": "rest", "title": "REST"}, {"id": "typescript", "title": "TypeScript"}, {"id": "java", "title": "Java"}]} values={["python", "csharp", "rest", "typescript", "java"]} defaultValue="python">
  ## Use Browser Automation tool with agents example

  The following TypeScript sample demonstrates how to create an agent with Browser Automation tool, perform web browsing tasks, and process streaming responses with browser automation events. For a JavaScript version of this sample, see the [JavaScript sample for Browser Automation tool](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/ai/ai-projects/samples/v2-beta/javascript/agents/tools/agentBrowserAutomation.js) in the Azure SDK for JavaScript repository on GitHub.

  ```typescript theme={null}
  import { DefaultAzureCredential } from "@azure/identity";
  import { AIProjectClient } from "@azure/ai-projects";

  // Format: "https://resource_name.ai.azure.com/api/projects/project_name"
  const PROJECT_ENDPOINT = "your_project_endpoint";
  const BROWSER_CONNECTION_ID = "your-browser-automation-connection-id";

  const handleBrowserCall = (item: any) => {
    // TODO: support browser_automation_preview_call schema
    const callId = item.call_id;
    const argumentsStr = item.arguments;

    // Parse the arguments string into a dictionary
    let query = null;
    if (argumentsStr && typeof argumentsStr === "string") {
      try {
        const argumentsObj = JSON.parse(argumentsStr);
        query = argumentsObj.query;
      } catch (e) {
        console.error("Failed to parse arguments:", e);
      }
    }

    console.log(`Call ID: ${callId ?? "None"}`);
    console.log(`Query arguments: ${query ?? "None"}`);
  };

  export async function main(): Promise<void> {
    // Create clients to call Foundry API
    const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
    const openai = project.getOpenAIClient();

    console.log("Creating agent with Browser Automation tool...");

    const agent = await project.agents.createVersion("MyAgent", {
      kind: "prompt",
      model: "gpt-4.1-mini",
      instructions: `You are an Agent helping with browser automation tasks. 
              You can answer questions, provide information, and assist with various tasks 
              related to web browsing using the Browser Automation tool available to you.`,
      // Define Browser Automation tool
      tools: [
        {
          type: "browser_automation_preview",
          browser_automation_preview: {
            connection: {
              project_connection_id: BROWSER_CONNECTION_ID,
            },
          },
        },
      ],
    });
    console.log(`Agent created (id: ${agent.id}, name: ${agent.name}, version: ${agent.version})`);

    console.log("\nSending browser automation request with streaming...");
    const streamResponse = await openai.responses.create(
      {
        input: `Your goal is to report the percent of Microsoft year-to-date stock price change.
              To do that, go to the website finance.yahoo.com.
              At the top of the page, you will find a search bar.
              Enter the value 'MSFT', to get information about the Microsoft stock price.
              At the top of the resulting page you will see a default chart of Microsoft stock price.
              Click on 'YTD' at the top of that chart, and report the percent value that shows up just below it.`,
        stream: true,
      },
      {
        body: {
          agent: { name: agent.name, type: "agent_reference" },
          tool_choice: "required",
        },
      },
    );

    // Process the streaming response
    for await (const event of streamResponse) {
      if (event.type === "response.created") {
        console.log(`Follow-up response created with ID: ${event.response.id}`);
      } else if (event.type === "response.output_text.delta") {
        process.stdout.write(event.delta);
      } else if (event.type === "response.output_text.done") {
        console.log("\n\nFollow-up response done!");
      } else if (
        event.type === "response.output_item.done" ||
        event.type === "response.output_item.added"
      ) {
        const item = event.item as any;
        if (item.type === "browser_automation_preview_call") {
          handleBrowserCall(item);
        }
      } else if (event.type === "response.completed") {
        console.log("\nFollow-up completed!");
      }
    }

    // Clean up resources by deleting the agent version
    // This prevents accumulation of unused resources in your project
    console.log("\nCleaning up resources...");
    await project.agents.deleteVersion(agent.name, agent.version);
    console.log("Agent deleted");

    console.log("\nBrowser Automation sample completed!");
  }

  main().catch((err) => {
    console.error("The sample encountered an error:", err);
  });
  ```

  ### What this code does

  This example creates an agent version with the Browser Automation tool enabled, sends a prompt that requires tool usage, and processes streaming events, including browser automation call events, as they arrive.

  ### Required inputs

  * A Foundry project endpoint and a browser automation connection ID. See [Configuration](#configuration) for details.

  ### Expected output

  You see an "Agent created ..." message, streaming text output, and optionally, browser call details when the tool is invoked. The output varies based on the website content and model behavior.
</ZoneContent>

<ZoneContent group="csharp__java__python__rest__typescript" value="java" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}, {"id": "rest", "title": "REST"}, {"id": "typescript", "title": "TypeScript"}, {"id": "java", "title": "Java"}]} values={["python", "csharp", "rest", "typescript", "java"]} defaultValue="python">
  ## Use browser automation in a Java agent

  Add the dependency to your `pom.xml`:

  ```xml theme={null}
  <dependency>
      <groupId>com.azure</groupId>
      <artifactId>azure-ai-agents</artifactId>
      <version>2.2.0</version>
  </dependency>
  ```

  ### Create an agent with browser automation

  ```java theme={null}
  import com.azure.ai.agents.AgentsClient;
  import com.azure.ai.agents.AgentsClientBuilder;
  import com.azure.ai.agents.ResponsesClient;
  import com.azure.ai.agents.models.*;
  import com.azure.identity.DefaultAzureCredentialBuilder;
  import com.openai.models.responses.Response;
  import com.openai.models.responses.ResponseCreateParams;

  import java.util.Collections;

  public class BrowserAutomationExample {
      public static void main(String[] args) {
          // Format: "https://resource_name.ai.azure.com/api/projects/project_name"
          String projectEndpoint = "your_project_endpoint";
          String browserConnectionId = "your-browser-automation-connection-id";

          AgentsClientBuilder builder = new AgentsClientBuilder()
              .credential(new DefaultAzureCredentialBuilder().build())
              .endpoint(projectEndpoint);

          AgentsClient agentsClient = builder.buildAgentsClient();
          ResponsesClient responsesClient = builder.buildResponsesClient();

          // Create browser automation tool with connection configuration
          BrowserAutomationPreviewTool browserTool = new BrowserAutomationPreviewTool(
              new BrowserAutomationToolParameters(
                  new BrowserAutomationToolConnectionParameters(browserConnectionId)
              )
          );

          // Create agent with browser automation tool
          PromptAgentDefinition agentDefinition = new PromptAgentDefinition("gpt-4.1-mini")
              .setInstructions("You are a helpful assistant that can interact with web pages.")
              .setTools(Collections.singletonList(browserTool));

          AgentVersionDetails agent = agentsClient.createAgentVersion("browser-agent", agentDefinition);
          System.out.printf("Agent created: %s (version %s)%n", agent.getName(), agent.getVersion());

          // Create a response
          AgentReference agentReference = new AgentReference(agent.getName())
              .setVersion(agent.getVersion());

          Response response = responsesClient.createAzureResponse(
              new AzureCreateResponseOptions().setAgentReference(agentReference),
              ResponseCreateParams.builder()
                  .input("Navigate to microsoft.com and summarize the main content"));

          System.out.println("Response: " + response.output());

          // Clean up
          agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion());
      }
  }
  ```
</ZoneContent>

## Limitations

* **Trusted sites only**: Use this tool only with sites you trust. Avoid pages that prompt for credentials, payments, or other sensitive actions.
* **Page volatility**: Web pages can change at any time. Your agent might fail if the page layout, labels, or navigation flows change. Build error handling into your workflows.
* **Complex single-page applications**: JavaScript-heavy SPAs with dynamic content might not render correctly.

## Cost considerations

This tool uses a Playwright workspace resource to run browser sessions. Review the Playwright workspace documentation for pricing and usage details. For guidance on optimizing tool usage, see [Best practices for using tools in Microsoft Foundry Agent Service](/agents/tool-best-practice).

## Troubleshooting

### The agent doesn't use the tool

* Confirm you created the agent with the Browser Automation tool enabled.
* In your request, require tool usage (for example, `tool_choice="required"`).
* Use tracing in Microsoft Foundry to confirm whether a tool call occurred. For guidance, see [Best practices for using tools in Microsoft Foundry Agent Service](/agents/tool-best-practice).

### Connection or authorization errors

* Confirm the browser automation connection ID matches the Playwright workspace connection resource ID in your project.
* Confirm the project identity has access to the Playwright workspace resource.
* If you recently rotated the Playwright access token, update the Foundry project connection key.

### Python SDK errors

* **Workspace not found**: Verify your project endpoint uses the correct format: `https://{account-name}.services.ai.azure.com/api/projects/{project-name}`. Don't use the legacy Azure ML endpoint format.
* **Unexpected keyword argument errors**: Ensure you're using the latest version of `azure-ai-projects`. Run `pip install "azure-ai-projects>=2.0.0" --upgrade` to update.
* **Import errors**: Install all required packages: `pip install "azure-ai-projects>=2.0.0"`.

### Requests time out

Browser automation can take longer than typical requests.

* Increase the client timeout (the C# sample sets a 5-minute timeout).
* Reduce the scope of your prompt (for example, fewer pages and fewer interactions).

## Clean up

* Delete the agent version you created for testing.
* Revoke or rotate the Playwright access token if you no longer need it.
* Remove the project connection if it’s no longer required. For more information, see [Add a connection in Microsoft Foundry](../../../how-to/connections-add).

## Example scenarios

* Form filling: Handles diverse form types with validation, DOM, authentication, compliance, and supporting multi-turn reasoning.

* Web scraping: Navigates authenticated sites to scrape, compare, and structure data across sources.

## Transparency note

Review the [transparency note](../../../responsible-ai/agents/transparency-note#enabling-autonomous-actions-with-or-without-human-input-through-action-tools) when using this tool. The Browser Automation tool is a tool that can perform real-world browser tasks through natural language prompts, enabling automated browsing activities without human intervention.

Review the [responsible AI considerations](../../../responsible-ai/agents/transparency-note#considerations-when-choosing-a-use-case) when using this tool.

## Related content

* [Best practices for using tools in Microsoft Foundry Agent Service](/agents/tool-best-practice)
* [Computer use tool for agents](/tools-and-knowledge/computer-use)
* [Add a connection in Microsoft Foundry](../../../how-to/connections-add)
* [Quickstart: Create your first agent](/get-started/get-started-code)
