Browser Automation API · /automate
Automate the web in a single API call.
Hand it a task in plain language and it navigates, clicks, fills forms, and completes multi-step flows on pages you don't control. The browser and the model both run on Tabstack. You just make the call.
agent.automate · streaming
Result
“Delta DL 1180 · $228 nonstop, departs 10:50a, lands 7:35p. The cheapest one that clears rush hour.”
Fully managed
One call, not a framework to run
The browser and the model both run on Tabstack, so there's no framework to install, no model to wire in, and no browser to host. You make one call instead of standing up a browser-automation stack.
Features
- ✓One /automate call runs the whole task
- ✓Streams task events as it works (SSE)
- ✓Returns the finished result, not raw page data
import Tabstack from '@tabstack/sdk'
const client = new Tabstack()
const stream = await client.agent.automate({
task: 'Find the pricing for the Enterprise plan and return the monthly cost and what is included',
url: 'https://example.com/pricing'
})
try {
for await (const event of stream) {
if (event.event === 'task:completed') { console.log(event.data.finalAnswer) }
if (event.event === 'error') { console.error(event.data.error.message) }
if (event.event === 'done') break
}
} catch (err) { console.error(err) }Screenshot agents send
an imageA full-page image on every action. Thousands of vision tokens.
Tabstack sends
the accessibility treeCompact structured text. 60-80% fewer tokens.
Cost at scale
60-80% fewer tokens per action
Tabstack reads the accessibility tree instead of taking screenshots, so every action costs a fraction of what vision-based agents spend. In our benchmarks that is a 60-80% reduction: a real cost difference at scale, not a minor optimization.
Features
- ✓Accessibility-tree engine instead of screenshots
- ✓Powered by Pilo, open source you can self-host
- ✓Runs many tasks concurrently at scale
Reliability
Handles the hard pages, asks about the rest
It works on the JS-heavy, dynamic, and authenticated pages that brittle scripts choke on. When it hits something it doesn't have, like a login, it pauses to ask instead of guessing or failing. And guardrails keep it inside the actions you allow, so you stay in control of what it does.
Features
- ✓Works on JS-heavy, dynamic, and authenticated pages
- ✓Pauses for human input with interactive: true
- ✓Scopes what it can do with guardrails
// Interactive mode: the agent pauses instead of guessing
const stream = await client.agent.automate({
task: 'Log in and check my account balance',
url: 'https://example.com/login',
interactive: true
})
try {
for await (const event of stream) {
if (event.event === 'interactive:form_data:request') {
const data = event.data as { requestId: string }
if (!data.requestId)