AgentKit Integration
AgentKit is a TypeScript framework by Inngest for building fault-tolerant AI agents with tools, state, and multi-agent networks. By connecting AgentKit to Browserless, your agents can browse the web with stealth capabilities, CAPTCHA solving, and residential proxies without managing browser infrastructure.
- Node.js 18 or higher
- Browserless API token (available in your account dashboard)
- An LLM API key (Anthropic, OpenAI, etc.), required for the agent to reason and call tools
Step-by-Step Setup
Get your API keys
Go to your Browserless account dashboard and copy your API token.
Then set your environment variables:
- .env file
- Command line
BROWSERLESS_API_KEY=your-browserless-token
ANTHROPIC_API_KEY=your-anthropic-keyexport BROWSERLESS_API_KEY=your-browserless-token
export ANTHROPIC_API_KEY=your-anthropic-keyInstall dependencies
AgentKit requires
inngestas a peer dependency. Install both alongside Playwright and Zod:- npm
- yarn
- pnpm
npm install @inngest/agent-kit inngest playwright-core zodyarn add @inngest/agent-kit inngest playwright-core zodpnpm add @inngest/agent-kit inngest playwright-core zodCreate a Browserless tool
Create a file called
index.ts. Start by defining a tool that connects to Browserless using Playwright'sconnectOverCDPmethod:import { createTool } from "@inngest/agent-kit";
import { z } from "zod";
import { chromium } from "playwright-core";
const scrapeHackerNews = createTool({
name: "scrape_hackernews",
description: "Get the top stories from Hacker News",
parameters: z.object({
limit: z.number().describe("Number of stories to fetch").default(5),
}),
handler: async ({ limit }, { step }) => {
const scrape = async () => {
const browser = await chromium.connectOverCDP(
`wss://production-sfo.browserless.io?token=${process.env.BROWSERLESS_API_KEY}`
);
try {
const page = await browser.newPage();
await page.goto("https://news.ycombinator.com");
const stories = await page.evaluate((limit) => {
const items = document.querySelectorAll(".athing");
return Array.from(items)
.slice(0, limit)
.map((item) => {
const titleEl = item.querySelector(".titleline > a");
const subtext = item.nextElementSibling;
const scoreEl = subtext?.querySelector(".score");
return {
title: titleEl?.textContent,
url: titleEl?.getAttribute("href"),
points: scoreEl?.textContent || "0 points",
};
});
}, limit);
return stories;
} finally {
await browser.close();
}
};
return await step?.run("scrape-hn", scrape) ?? await scrape();
},
});When running inside an Inngest function,
step.run()ensures the operation only executes once, even if the agent retries. The?? await scrape()fallback lets the same tool work in standalone mode without Inngest.Create an agent and network
Add the agent and network definitions to the same file. Pass the tool directly to the agent's
toolsarray:import {
anthropic,
createAgent,
createNetwork,
} from "@inngest/agent-kit";
const newsAgent = createAgent({
name: "hackernews_agent",
description: "Fetches and summarizes Hacker News stories",
system: "You fetch top stories from Hacker News and provide summaries.",
tools: [scrapeHackerNews],
});
const network = createNetwork({
name: "news_network",
agents: [newsAgent],
maxIter: 3,
defaultModel: anthropic({
model: "claude-sonnet-4-20250514",
defaultParameters: {
max_tokens: 4096,
},
}),
});Run the agent
Add the following to the same file to run the network with a prompt:
const result = await network.run(
"Get the top 5 stories from Hacker News and summarize them"
);
console.log(result);Run the script:
npx tsx ./index.tsYou should see the agent fetch and summarize the top Hacker News stories.
How It Works
- Connection: Playwright connects to Browserless via WebSocket using
connectOverCDP - Tool execution: The agent calls your tool, which runs browser operations through Browserless
- Cleanup: The browser closes in a
finallyblock to prevent session leaks
Advanced Configuration
Stealth mode
For sites with bot detection, use a stealth route:
const browser = await chromium.connectOverCDP(
`wss://production-sfo.browserless.io/stealth?token=${process.env.BROWSERLESS_API_KEY}`
);
Residential proxies
Route traffic through residential IPs for geo-targeting and rate-limit avoidance:
const browser = await chromium.connectOverCDP(
`wss://production-sfo.browserless.io?token=${process.env.BROWSERLESS_API_KEY}&proxy=residential&proxyCountry=us`
);
Regional endpoints
Pick the region closest to your users or target sites:
| Region | Endpoint |
|---|---|
| US West (San Francisco) | wss://production-sfo.browserless.io |
| Europe (London) | wss://production-lon.browserless.io |
| Europe (Amsterdam) | wss://production-ams.browserless.io |
Resources
FAQ & Troubleshooting
How does an AgentKit tool connect to Browserless?
Use Playwright's connectOverCDP method inside your tool's handler, pointing at your Browserless WebSocket URL with your token, as shown in step 3 above.
My tool's browsing gets blocked by bot detection
Switch to the stealth route (wss://production-sfo.browserless.io/stealth?token=...) and add a residential proxy, as shown in Advanced Configuration above.
Why does the tool call browser.close() in a finally block?
Browserless sessions consume units for as long as they're open. Closing in finally guarantees cleanup even if the tool throws, preventing leaked sessions from running until they time out.