Mastra.ai + Anchor: Browser Agents in TypeScript

Hands On
Jun 26
by Idan Raman
Mastra.ai + Anchor: Browser Agents in TypeScript cover image

Mastra.ai ships a modern TypeScript framework for building production-grade AI agents. It handles model routing, tool dispatch, and structured output without a bloated SDK. Pair it with Anchor's isolated cloud browser sessions and you get agents that can navigate real websites, handle logins, fill forms, and extract structured data — all with fingerprint stability, proxy support, and clean session isolation built in.

This guide walks through the full setup in about 60 lines of TypeScript.

Why Mastra + Anchor?

Mastra’s createTool primitive wraps any async function into something an agent can call. Anchor’s session API returns a CDP URL you can hand to Playwright in one line. The combination is deliberately minimal: no framework wrappers, no DSL — just typed tools and isolated browser sessions.

  • Isolation — Each agent task gets its own browser session. No cookie bleed, no shared state between runs.
  • Stealth — Anchor handles fingerprinting and anti-bot headers automatically, so your agent passes Cloudflare and similar checks.
  • Profiles — Persist authenticated sessions across runs without re-logging in every time.
  • TypeScript-first — Both Mastra and the Anchor SDK are fully typed.

What We’re Building

A research agent that takes a list of company names, opens an isolated Anchor browser session per company, navigates to their homepage, and returns a structured one-sentence summary of each. The full flow from prompt to output takes under 30 seconds.

Setup

npm install @mastra/core @ai-sdk/anthropic anchorbrowser playwright zod
export ANCHOR_API_KEY="your-anchor-api-key"
export ANTHROPIC_API_KEY="your-anthropic-api-key"

The Browser Tool

Wrap an Anchor session and a Playwright page into createTool. The tool takes a URL and a question, navigates to the page, and returns the extracted text content.

// tools/browse-and-extract.ts
import { createTool } from '@mastra/core/tools';
import { chromium } from 'playwright';
import AnchorClient from 'anchorbrowser';
import { z } from 'zod';

const anchorClient = new AnchorClient({ apiKey: process.env.ANCHOR_API_KEY });

export const browseAndExtract = createTool({
  id: 'browse-and-extract',
  description: 'Opens a URL in an isolated cloud browser and extracts page content',
  inputSchema: z.object({
    url: z.string().url().describe('The page to visit'),
    question: z.string().describe('What to look for on the page'),
  }),
  outputSchema: z.object({
    content: z.string(),
    url: z.string(),
  }),
  execute: async ({ context }) => {
    const session = await anchorClient.sessions.create();
    const browser = await chromium.connectOverCDP(session.data.cdp_url);

    try {
      const page = await browser.newPage();
      await page.goto(context.url, { waitUntil: 'domcontentloaded' });

      // Cap at 4 000 chars to control token cost
      const content = await page.evaluate(() =>
        document.body.innerText.slice(0, 4000)
      );

      return { content, url: context.url };
    } finally {
      await browser.close();
      await anchorClient.sessions.stop(session.data.id);
    }
  },
});

Defining the Agent

// agents/research-agent.ts
import { Agent } from '@mastra/core/agent';
import { anthropic } from '@ai-sdk/anthropic';
import { browseAndExtract } from '../tools/browse-and-extract';

export const researchAgent = new Agent({
  name: 'Web Research Agent',
  instructions: `You are a research assistant. When given company names, use the
  browse-and-extract tool to visit each company's homepage. Return a bullet list
  with one sentence per company describing what they do.`,
  model: anthropic('claude-sonnet-4-6'),
  tools: { browseAndExtract },
});

Running It

// index.ts
import { Mastra } from '@mastra/core';
import { researchAgent } from './agents/research-agent';

const mastra = new Mastra({ agents: { researchAgent } });
const agent = mastra.getAgent('researchAgent');

const result = await agent.generate(
  'Research these companies: Stripe, Linear, Vercel'
);

console.log(result.text);

Expected output:

- Stripe: Payments infrastructure that helps businesses accept money online and manage financial operations at scale.
- Linear: A project management tool built for software teams that prioritizes speed, keyboard shortcuts, and minimal UI.
- Vercel: A cloud platform for deploying frontend applications and serverless functions with zero configuration.

Persistent Profiles for Authenticated Sessions

If your agent needs to stay logged in, use Anchor’s profile feature. A profile persists cookies and local storage between sessions — your agent logs in once, and every subsequent run reuses that authenticated state.

// Create a named profile once, then reuse it on every run
const profile = await anchorClient.profiles.create({ name: 'dashboard-session' });

const session = await anchorClient.sessions.create({
  profileId: profile.data.id,
});

Combine this with OmniConnect to handle full OAuth flows without hardcoding credentials.

Production Tips

  • Clean up sessions — Always call anchorClient.sessions.stop(session.data.id) in a finally block. Leaked sessions count against your concurrent session limit.
  • Limit content size — Slice page text before returning it (e.g. .slice(0, 4000)). A raw 50 KB homepage can burn thousands of tokens per tool call.
  • Route by region — Pass proxyConfig: { country: 'us' } to sessions.create() for geo-specific content like regional pricing pages.
  • Retry on connect — Playwright’s connectOverCDP can throw on cold starts. Wrap it in a short retry loop before surfacing errors to the agent.

What’s Next

Mastra’s createWorkflow lets you chain this into larger pipelines — research with the browser, analyze with a second agent, write a report as a third step. The tool you built here plugs into any of those workflows without changes.

The Anchor SDK also supports parallel session creation. If your agent fans out across dozens of pages in the same task, each gets its own isolated browser running concurrently — Anchor handles up to 5 000 simultaneous sessions, so the bottleneck will be your LLM context budget, not the infrastructure.

Try Anchor free →

Stay ahead in browser automation

We respect your inbox. Privacy policy

Welcome aboard! Thanks for signing up
Oops! Something went wrong while submitting the form.