Automate Features
The Automate operator executes complex browser automation tasks using natural language instructions. Unlike Extract and Generate which work with static content, Automate can interact with pages, fill forms, click buttons, and perform multi-step workflows.
Overview
The automate operator is accessed through your TABStack client instance:
- TypeScript
- JavaScript
import { TABStack } from '@tabstack/sdk';
const tabs = new TABStack({
apiKey: process.env.TABSTACK_API_KEY!
});
// Access automate methods
for await (const event of tabs.automate.execute(task, options)) {
// Handle streaming events
}
const { TABStack } = require('@tabstack/sdk');
const tabs = new TABStack({
apiKey: process.env.TABSTACK_API_KEY
});
// Access automate methods
for await (const event of tabs.automate.execute(task, options)) {
// Handle streaming events
}
Key Features
- Natural Language Tasks: Describe what you want to accomplish in plain English
- Real-Time Streaming: Get live updates as the automation progresses
- Multi-Step Workflows: Execute complex sequences of actions
- Form Handling: Fill and submit forms automatically
- Data Extraction: Extract data during automation
- Guardrails: Set safety constraints to control automation behavior
Execute Automation
The execute method returns an async generator that streams events as the automation runs.
Basic Usage
- TypeScript
- JavaScript
for await (const event of tabs.automate.execute(
'Find the top 3 trending repositories on GitHub and extract their names and star counts',
{
url: 'https://github.com/trending',
guardrails: 'browse and extract only'
}
)) {
console.log(`Event: ${event.type}`);
if (event.type === 'task:completed') {
const result = event.data.get('finalAnswer');
console.log('Automation completed:', result);
}
}
for await (const event of tabs.automate.execute(
'Find the top 3 trending repositories on GitHub and extract their names and star counts',
{
url: 'https://github.com/trending',
guardrails: 'browse and extract only'
}
)) {
console.log(`Event: ${event.type}`);
if (event.type === 'task:completed') {
const result = event.data.get('finalAnswer');
console.log('Automation completed:', result);
}
}
Understanding the Async Generator
The execute method uses an async generator to stream events:
- TypeScript
- JavaScript
// The for await...of loop handles the streaming automatically
for await (const event of tabs.automate.execute(task, options)) {
// Each event has:
// - type: string (event type)
// - data: EventData (event-specific data)
console.log(`${event.type}:`, event.data.getRaw());
}
// The for await...of loop handles the streaming automatically
for await (const event of tabs.automate.execute(task, options)) {
// Each event has:
// - type: string (event type)
// - data: EventData (event-specific data)
console.log(`${event.type}:`, event.data.getRaw());
}
Event Types
The automation streams different types of events as it progresses:
Task Events
| Event Type | Description | Key Data Fields |
|---|---|---|
start | Automation is starting | - |
task:setup | Task is being initialized | task |
task:started | Task execution began | task |
task:completed | Task finished successfully | finalAnswer, status |
task:aborted | Task was aborted | reason |
task:validated | Task result validated | validation |
task:validation_error | Validation failed | error |
Agent Events
| Event Type | Description | Key Data Fields |
|---|---|---|
agent:processing | Agent is processing | status |
agent:status | Status update | message |
agent:step | Completed a step | step, description |
agent:action | Performing an action | action, target |
agent:reasoned | Agent's reasoning | thought, plan |
agent:extracted | Data was extracted | extractedData |
agent:waiting | Waiting for page load/action | reason |
Browser Events
| Event Type | Description | Key Data Fields |
|---|---|---|
browser:navigated | Page navigation occurred | url |
browser:action_started | Browser action starting | action |
browser:action_completed | Browser action finished | action, result |
browser:screenshot_captured | Screenshot taken | screenshotId |
Stream Control Events
| Event Type | Description |
|---|---|
complete | Automation stream finished |
done | Final event (always sent) |
error | An error occurred |
Real-World Examples
Example 1: Web Scraping with Navigation
- TypeScript
- JavaScript
console.log('Starting GitHub trending scraper...\n');
for await (const event of tabs.automate.execute(
'Navigate to GitHub trending, find the top 5 repositories, and for each extract: name, description, primary language, and star count',
{
url: 'https://github.com/trending',
guardrails: 'browse and extract only',
maxIterations: 50
}
)) {
// Log different event types
switch (event.type) {
case 'agent:status':
console.log(`Status: ${event.data.get('message')}`);
break;
case 'agent:action':
console.log(`Action: ${event.data.get('action')}`);
break;
case 'browser:navigated':
console.log(`Navigated to: ${event.data.get('url')}`);
break;
case 'agent:extracted':
const extracted = event.data.get('extractedData');
console.log('Extracted data:', JSON.stringify(extracted, null, 2));
break;
case 'task:completed':
const result = event.data.get('finalAnswer');
console.log('\n✅ Automation completed!');
console.log('Final result:', result);
break;
case 'error':
console.error('❌ Error:', event.data.get('error'));
break;
}
}
console.log('Starting GitHub trending scraper...\n');
for await (const event of tabs.automate.execute(
'Navigate to GitHub trending, find the top 5 repositories, and for each extract: name, description, primary language, and star count',
{
url: 'https://github.com/trending',
guardrails: 'browse and extract only',
maxIterations: 50
}
)) {
// Log different event types
switch (event.type) {
case 'agent:status':
console.log(`Status: ${event.data.get('message')}`);
break;
case 'agent:action':
console.log(`Action: ${event.data.get('action')}`);
break;
case 'browser:navigated':
console.log(`Navigated to: ${event.data.get('url')}`);
break;
case 'agent:extracted':
const extracted = event.data.get('extractedData');
console.log('Extracted data:', JSON.stringify(extracted, null, 2));
break;
case 'task:completed':
const result = event.data.get('finalAnswer');
console.log('\n✅ Automation completed!');
console.log('Final result:', result);
break;
case 'error':
console.error('❌ Error:', event.data.get('error'));
break;
}
}
Example 2: Form Filling
- TypeScript
- JavaScript
console.log('Filling contact form...\n');
const formData = {
name: 'Alex Johnson',
email: '[email protected]',
company: 'Example Corp',
message: 'I am interested in learning more about your product offerings.'
};
for await (const event of tabs.automate.execute(
'Fill out the contact form with the provided data and submit it',
{
url: 'https://company.example.com/contact',
data: formData,
guardrails: 'do not navigate away from the domain',
maxIterations: 30
}
)) {
switch (event.type) {
case 'agent:action':
const action = event.data.get('action');
const target = event.data.get('target');
console.log(`Action: ${action} on ${target || 'page'}`);
break;
case 'agent:status':
console.log(`Status: ${event.data.get('message')}`);
break;
case 'task:completed':
console.log('\n✅ Form submitted successfully!');
const confirmation = event.data.get('finalAnswer');
console.log('Confirmation:', confirmation);
break;
case 'error':
console.error('❌ Error submitting form:', event.data.get('error'));
break;
}
}
console.log('Filling contact form...\n');
const formData = {
name: 'Alex Johnson',
email: '[email protected]',
company: 'Example Corp',
message: 'I am interested in learning more about your product offerings.'
};
for await (const event of tabs.automate.execute(
'Fill out the contact form with the provided data and submit it',
{
url: 'https://company.example.com/contact',
data: formData,
guardrails: 'do not navigate away from the domain',
maxIterations: 30
}
)) {
switch (event.type) {
case 'agent:action':
const action = event.data.get('action');
const target = event.data.get('target');
console.log(`Action: ${action} on ${target || 'page'}`);
break;
case 'agent:status':
console.log(`Status: ${event.data.get('message')}`);
break;
case 'task:completed':
console.log('\n✅ Form submitted successfully!');
const confirmation = event.data.get('finalAnswer');
console.log('Confirmation:', confirmation);
break;
case 'error':
console.error('❌ Error submitting form:', event.data.get('error'));
break;
}
}
Example 3: Multi-Step Workflow
- TypeScript
- JavaScript
console.log('Starting product research workflow...\n');
const steps: string[] = [];
const extractedData: any[] = [];
for await (const event of tabs.automate.execute(
`
1. Search for "wireless headphones" on the e-commerce site
2. Filter results by "customer rating" (4 stars and above)
3. Extract the top 3 products with: name, price, rating, and review count
4. Return the results as structured data
`,
{
url: 'https://shop.example.com',
guardrails: 'browse and extract only, do not add items to cart',
maxIterations: 100
}
)) {
switch (event.type) {
case 'agent:step':
const step = event.data.get('step');
const description = event.data.get('description');
steps.push(description);
console.log(`\nStep ${step}: ${description}`);
break;
case 'agent:action':
console.log(` → ${event.data.get('action')}`);
break;
case 'agent:extracted':
const data = event.data.get('extractedData');
extractedData.push(data);
console.log(' → Extracted:', data);
break;
case 'task:completed':
console.log('\n✅ Workflow completed!');
console.log(`\nCompleted ${steps.length} steps`);
const finalResult = event.data.get('finalAnswer');
console.log('\nFinal Results:');
console.log(JSON.stringify(finalResult, null, 2));
break;
case 'error':
console.error('\n❌ Workflow failed:', event.data.get('error'));
break;
}
}
console.log('Starting product research workflow...\n');
const steps = [];
const extractedData = [];
for await (const event of tabs.automate.execute(
`
1. Search for "wireless headphones" on the e-commerce site
2. Filter results by "customer rating" (4 stars and above)
3. Extract the top 3 products with: name, price, rating, and review count
4. Return the results as structured data
`,
{
url: 'https://shop.example.com',
guardrails: 'browse and extract only, do not add items to cart',
maxIterations: 100
}
)) {
switch (event.type) {
case 'agent:step':
const step = event.data.get('step');
const description = event.data.get('description');
steps.push(description);
console.log(`\nStep ${step}: ${description}`);
break;
case 'agent:action':
console.log(` → ${event.data.get('action')}`);
break;
case 'agent:extracted':
const data = event.data.get('extractedData');
extractedData.push(data);
console.log(' → Extracted:', data);
break;
case 'task:completed':
console.log('\n✅ Workflow completed!');
console.log(`\nCompleted ${steps.length} steps`);
const finalResult = event.data.get('finalAnswer');
console.log('\nFinal Results:');
console.log(JSON.stringify(finalResult, null, 2));
break;
case 'error':
console.error('\n❌ Workflow failed:', event.data.get('error'));
break;
}
}
Example 4: Progress Tracking with UI
Build a simple progress tracker:
- TypeScript
- JavaScript
interface ProgressState {
status: string;
currentStep: number;
totalSteps: number;
lastAction: string;
isComplete: boolean;
error?: string;
}
const progress: ProgressState = {
status: 'Starting...',
currentStep: 0,
totalSteps: 0,
lastAction: '',
isComplete: false
};
function displayProgress(progress: ProgressState) {
console.clear();
console.log('=== Automation Progress ===\n');
console.log(`Status: ${progress.status}`);
console.log(`Step: ${progress.currentStep}/${progress.totalSteps || '?'}`);
console.log(`Last Action: ${progress.lastAction}`);
if (progress.isComplete) {
console.log('\n✅ Complete!');
} else if (progress.error) {
console.log(`\n❌ Error: ${progress.error}`);
}
}
try {
for await (const event of tabs.automate.execute(
'Find and extract the top 5 blog posts',
{ url: 'https://blog.example.com' }
)) {
switch (event.type) {
case 'agent:status':
progress.status = event.data.get('message') || 'Processing...';
break;
case 'agent:step':
progress.currentStep = event.data.get('step') || 0;
break;
case 'agent:action':
progress.lastAction = event.data.get('action') || '';
break;
case 'task:completed':
progress.isComplete = true;
progress.status = 'Completed';
break;
case 'error':
progress.error = event.data.get('error');
break;
}
displayProgress(progress);
}
} catch (error) {
progress.error = error.message;
displayProgress(progress);
}
const progress = {
status: 'Starting...',
currentStep: 0,
totalSteps: 0,
lastAction: '',
isComplete: false,
error: null
};
function displayProgress(progress) {
console.clear();
console.log('=== Automation Progress ===\n');
console.log(`Status: ${progress.status}`);
console.log(`Step: ${progress.currentStep}/${progress.totalSteps || '?'}`);
console.log(`Last Action: ${progress.lastAction}`);
if (progress.isComplete) {
console.log('\n✅ Complete!');
} else if (progress.error) {
console.log(`\n❌ Error: ${progress.error}`);
}
}
try {
for await (const event of tabs.automate.execute(
'Find and extract the top 5 blog posts',
{ url: 'https://blog.example.com' }
)) {
switch (event.type) {
case 'agent:status':
progress.status = event.data.get('message') || 'Processing...';
break;
case 'agent:step':
progress.currentStep = event.data.get('step') || 0;
break;
case 'agent:action':
progress.lastAction = event.data.get('action') || '';
break;
case 'task:completed':
progress.isComplete = true;
progress.status = 'Completed';
break;
case 'error':
progress.error = event.data.get('error');
break;
}
displayProgress(progress);
}
} catch (error) {
progress.error = error.message;
displayProgress(progress);
}
Working with EventData
Each event includes an EventData object with helper methods:
- TypeScript
- JavaScript
for await (const event of tabs.automate.execute(task, options)) {
// Get a specific field with type safety
const message = event.data.get<string>('message');
// Get with a default value
const step = event.data.get<number>('step', 0);
// Get the raw data object
const rawData = event.data.getRaw();
console.log('All event data:', rawData);
// Check if a field exists
if (event.data.get('extractedData')) {
const data = event.data.get('extractedData');
// Process extracted data
}
}
for await (const event of tabs.automate.execute(task, options)) {
// Get a specific field
const message = event.data.get('message');
// Get with a default value
const step = event.data.get('step', 0);
// Get the raw data object
const rawData = event.data.getRaw();
console.log('All event data:', rawData);
// Check if a field exists
if (event.data.get('extractedData')) {
const data = event.data.get('extractedData');
// Process extracted data
}
}
Options Reference
AutomateExecuteOptions
| Option | Type | Default | Description |
|---|---|---|---|
url | string | - | Starting URL for the automation |
data | Record<string, unknown> | - | Context data (e.g., form fields to fill) |
guardrails | string | - | Safety constraints for automation behavior |
maxIterations | number | 50 | Maximum iterations (range: 1-100) |
maxValidationAttempts | number | 3 | Maximum validation retry attempts (range: 1-10) |
Guardrails
Guardrails are natural language constraints that control automation behavior:
// Examples of guardrails:
// Browse only, no modifications
guardrails: 'browse and extract only'
// Stay on specific domain
guardrails: 'do not navigate away from the domain'
// No purchases
guardrails: 'do not add items to cart or make purchases'
// Read-only operations
guardrails: 'read-only operations, do not submit forms or click buttons that modify data'
// Specific constraints
guardrails: 'only search and extract data, do not click on external links'
Best Practices
1. Be Specific with Instructions
// ❌ Vague
'Get some products'
// ✅ Specific
'Find the top 5 best-selling products in the Electronics category and extract their names, prices, and average ratings'
2. Set Appropriate Iteration Limits
// Simple task - lower limit
maxIterations: 30
// Complex multi-step workflow - higher limit
maxIterations: 100
3. Always Use Guardrails
Protect against unintended actions:
// ✅ Good: Clear guardrails
{
guardrails: 'browse and extract only, do not submit forms or make purchases'
}
// ❌ Risky: No guardrails
{
// Could potentially trigger unintended actions
}
4. Handle All Event Types
Don't just wait for completion - handle progress and errors:
for await (const event of tabs.automate.execute(task, options)) {
switch (event.type) {
case 'agent:status':
// Show progress
break;
case 'task:completed':
// Handle success
break;
case 'error':
// Handle errors
break;
case 'task:aborted':
// Handle aborted tasks
break;
}
}
5. Implement Timeouts
Add your own timeout logic for long-running automations:
const timeout = 300000; // 5 minutes
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
for await (const event of tabs.automate.execute(task, options)) {
if (controller.signal.aborted) {
console.log('Automation timed out');
break;
}
// Handle events
}
} finally {
clearTimeout(timeoutId);
}
6. Log Important Events
Keep track of the automation flow:
const log: string[] = [];
for await (const event of tabs.automate.execute(task, options)) {
const logEntry = `[${new Date().toISOString()}] ${event.type}: ${JSON.stringify(event.data.getRaw())}`;
log.push(logEntry);
if (event.type === 'task:completed' || event.type === 'error') {
// Save log to file or database
await saveLog(log);
}
}
Error Handling
Always wrap automation in try-catch blocks:
- TypeScript
- JavaScript
try {
for await (const event of tabs.automate.execute(task, options)) {
if (event.type === 'error') {
const error = event.data.get('error');
console.error('Automation error:', error);
// Handle gracefully
break;
}
if (event.type === 'task:completed') {
// Success
}
}
} catch (error) {
console.error('Fatal error:', error.message);
// Cleanup and notify
}
try {
for await (const event of tabs.automate.execute(task, options)) {
if (event.type === 'error') {
const error = event.data.get('error');
console.error('Automation error:', error);
// Handle gracefully
break;
}
if (event.type === 'task:completed') {
// Success
}
}
} catch (error) {
console.error('Fatal error:', error.message);
// Cleanup and notify
}
Next Steps
- Error Handling: Build robust applications with comprehensive error handling
- Extract Features: Learn about data extraction methods
- Generate Features: Discover AI-powered content transformation
- REST API Reference: See the underlying REST API endpoint