For AI agents: a documentation index is available at /llms.txt
Skip to main content

Connecting Mastra agents to Browserless

Mastra is a TypeScript framework for building AI agents, workflows, and tools. This guide connects a Mastra agent to Browserless two ways: as the browser behind Mastra's AgentBrowser, so the agent can click, type, and navigate, and as an MCP tool source for one-shot scraping and search.

Prerequisites
  • A Browserless API token from your account dashboard
  • Node.js 22.13 or higher
  • An LLM API key (Anthropic, OpenAI, etc.) for the agent's model
  • Familiarity with Mastra agents

Which approach to use​

ApproachUse it whenWhat the agent gets
AgentBrowser + BrowserlessThe agent has to interact with pages: log in, fill forms, click through flowsMastra's 16 browser tools (browser_goto, browser_click, browser_snapshot, ...) running on a Browserless session
Browserless MCP serverThe agent needs page content, search results, or crawls, without holding browser stateBrowserless MCP tools (browserless_smartscraper, browserless_search, browserless_crawl, ...)

You can give one agent both. If you'd rather hand off the whole browsing task instead of driving it step by step from Mastra, use the Browser Agent.

Connect AgentBrowser to Browserless​

  1. Set your API keys

    Copy your API token from the account dashboard, then set it with your model provider's key:

    BROWSERLESS_TOKEN=YOUR_API_TOKEN_HERE
    ANTHROPIC_API_KEY=your-anthropic-key
  2. Install dependencies

    npm install @mastra/core @mastra/agent-browser

    You don't need npx playwright install. With cdpUrl set, Browserless supplies the browser.

  3. Create the agent

    Create src/mastra/agents/browser-agent.ts. Pass your Browserless endpoint as cdpUrl and attach the browser to the agent:

    import { Agent } from "@mastra/core/agent";
    import { AgentBrowser } from "@mastra/agent-browser";

    const TOKEN = process.env.BROWSERLESS_TOKEN;

    export const browser = new AgentBrowser({
    // A CDP URL makes AgentBrowser connect instead of launching local Chromium.
    cdpUrl: `wss://production-sfo.browserless.io?token=${TOKEN}`,
    });

    export const browserAgent = new Agent({
    id: "browser-agent",
    name: "Browser Agent",
    model: "anthropic/claude-sonnet-5-5",
    browser,
    instructions: `You are a web research assistant.

    When interacting with pages:
    1. Use browser_snapshot to get the page state and element refs.
    2. Use the refs (like @e1, @e2) to target clicks and typing.
    3. Take another snapshot after each action to confirm the result.`,
    });
  4. Run the agent

    Create src/run.ts:

    import "dotenv/config";
    import { browser, browserAgent } from "./mastra/agents/browser-agent";

    async function main() {
    try {
    const result = await browserAgent.generate(
    "Go to https://news.ycombinator.com and list the titles of the top 3 stories."
    );
    console.log(result.text);
    } finally {
    // Close explicitly so the Browserless session ends now, not at its timeout.
    await browser.close();
    }
    }

    main();
    npm install dotenv && npx tsx src/run.ts

    Response:

    Here are the top 3 stories on Hacker News right now:

    1. <story title>
    2. <story title>
    3. <story title>

How it works​

  • cdpUrl switches AgentBrowser from launching Chromium to connecting over CDP. Browserless starts a session when the agent first uses a browser tool.
  • With cdpUrl set, every thread shares one browser. Mastra throws if you combine cdpUrl with scope: 'thread', because it can't spawn separate browsers over one CDP connection. To isolate conversations, create a separate AgentBrowser and agent for each one, so each gets its own Browserless session.
  • cdpUrl also accepts a function, so you can build the URL when the browser connects, for example to pick a region or proxy country at runtime:
const browser = new AgentBrowser({
cdpUrl: () =>
`wss://production-sfo.browserless.io?token=${process.env.BROWSERLESS_TOKEN}&proxy=residential&proxyCountry=us`,
});

Add Browserless MCP tools​

For scraping, search, and crawling, connect Mastra's MCPClient to the hosted Browserless MCP server. Each tool call is a single request, so there's no session for the agent to manage.

npm install @mastra/core @mastra/mcp dotenv

Top-level await needs ES modules, so set "type": "module" in package.json before running this file with npx tsx.

import "dotenv/config";
import { Agent } from "@mastra/core/agent";
import { MCPClient } from "@mastra/mcp";

const mcp = new MCPClient({
servers: {
browserless: {
url: new URL("https://mcp.browserless.io/mcp"),
requestInit: {
headers: { Authorization: `Bearer ${process.env.BROWSERLESS_TOKEN}` },
},
},
},
});

try {
// listTools() swallows connection errors and returns no tools, so check explicitly.
const { tools, errors } = await mcp.listToolsWithErrors();
if (errors.browserless) {
throw new Error(`Browserless MCP server unavailable: ${errors.browserless}`);
}

const researchAgent = new Agent({
id: "research-agent",
name: "Research Agent",
model: "anthropic/claude-sonnet-5-5",
instructions: "Use the Browserless tools to search the web and read pages before answering.",
tools,
});

const result = await researchAgent.generate(
"Scrape https://browserless.io/pricing and summarize the plans."
);
console.log(result.text);
} finally {
// Close the MCP connection even if a call fails, so the process can exit.
await mcp.disconnect();
}

Response:

Browserless offers <n> plans: ...

Tool names arrive namespaced by server, for example browserless_browserless_smartscraper. See the MCP tool reference for what each tool does.

Configure the browser session​

For the AgentBrowser route, set every Browserless session option on cdpUrl. Routes such as /stealth go in the path, and options such as proxies and timeouts go in the query string.

Stealth​

Use the stealth route for sites with bot detection:

cdpUrl: `wss://production-sfo.browserless.io/stealth?token=${TOKEN}`,

Residential proxies​

Route traffic through residential IPs for geo-targeted pages or sites that rate-limit datacenter IPs:

cdpUrl: `wss://production-sfo.browserless.io?token=${TOKEN}&proxy=residential&proxyCountry=us`,

See proxies for every proxy option.

Regional and self-hosted endpoints​

DeploymentcdpUrl
US West (San Francisco)wss://production-sfo.browserless.io?token=${TOKEN}
Europe (London)wss://production-lon.browserless.io?token=${TOKEN}
Europe (Amsterdam)wss://production-ams.browserless.io?token=${TOKEN}
Self-hosted Dockerws://localhost:3000?token=${TOKEN}

FAQ & Troubleshooting​

I'm getting browser executable is missing

AgentBrowser is launching locally because cdpUrl is empty. Check that BROWSERLESS_TOKEN is loaded before the agent module is imported. Import dotenv/config first, or export the variable in your shell.

Two conversations are seeing each other's pages

With cdpUrl set, threads share one browser, and Mastra rejects scope: 'thread' alongside cdpUrl. Create a separate AgentBrowser and agent per conversation so each gets its own Browserless session, and close each browser when its conversation ends.

The session closes partway through a long task

Browserless sessions have a timeout. Add a timeout query parameter in milliseconds to cdpUrl, for example &timeout=600000, up to your plan's limit. See launch options.

The agent gets blocked or hits CAPTCHAs

Switch cdpUrl to the stealth route and add a residential proxy. For sites that still block, the Browser Agent handles CAPTCHA solving for you.

Next steps​

Was this page helpful?