---
title: Automate Features | Tabstack
description: Execute complex browser automation tasks using natural language with the Tabstack TypeScript SDK.
---

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` method is accessed through the `agent` client on your Tabstack instance:

- [TypeScript](#tab-panel-274)
- [JavaScript](#tab-panel-275)

```
import Tabstack from "@tabstack/sdk";


const client = new Tabstack({
  apiKey: process.env.TABSTACK_API_KEY!,
});


// Access agent automate method
const stream = await client.agent.automate({
  task: "Your task description",
  url: "https://example.com",
});


for await (const event of stream) {
  // Handle streaming events
  console.log(event.event, event.data);
}
```

```
const Tabstack = require("@tabstack/sdk").default;


const client = new Tabstack({
  apiKey: process.env.TABSTACK_API_KEY,
});


// Access agent automate method
const stream = await client.agent.automate({
  task: "Your task description",
  url: "https://example.com",
});


for await (const event of stream) {
  // Handle streaming events
  console.log(event.event, event.data);
}
```

## 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 `automate` method returns an async iterable that streams events as the automation runs.

### Basic Usage

- [TypeScript](#tab-panel-276)
- [JavaScript](#tab-panel-277)

```
const stream = await client.agent.automate({
  task: "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",
});


for await (const event of stream) {
  console.log(`Event: ${event.event}`);


  if (event.event === "task:completed") {
    const result = event.data?.finalAnswer;
    console.log("Automation completed:", result);
  }
}
```

```
const stream = await client.agent.automate({
  task: "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",
});


for await (const event of stream) {
  console.log(`Event: ${event.event}`);


  if (event.event === "task:completed") {
    const result = event.data?.finalAnswer;
    console.log("Automation completed:", result);
  }
}
```

### Understanding the Stream

The `automate` method returns an async iterable to stream events:

- [TypeScript](#tab-panel-278)
- [JavaScript](#tab-panel-279)

```
// The for await...of loop handles the streaming automatically
const stream = await client.agent.automate({
  task: "Find products",
  url: "https://example.com",
});


for await (const event of stream) {
  // Each event has:
  // - event: string (event type)
  // - data: object (event-specific data)


  console.log(`${event.event}:`, event.data);
}
```

```
// The for await...of loop handles the streaming automatically
const stream = await client.agent.automate({
  task: "Find products",
  url: "https://example.com",
});


for await (const event of stream) {
  // Each event has:
  // - event: string (event type)
  // - data: object (event-specific data)


  console.log(`${event.event}:`, event.data);
}
```

## 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`, `url`, `plan`, `successCriteria`, `actionItems` |
| `task:completed`        | Task finished successfully | `finalAnswer`, `success`                                |
| `task:aborted`          | Task was aborted           | `reason`                                                |
| `task:validated`        | Task result validated      | `completionQuality`, `observation`, `finalAnswer`       |
| `task:validation_error` | Validation failed          | `error`                                                 |

### Agent Events

| Event Type         | Description                  | Key Data Fields                       |
| ------------------ | ---------------------------- | ------------------------------------- |
| `agent:processing` | Agent is processing          | `operation`, `hasScreenshot`          |
| `agent:status`     | Status update                | `message`                             |
| `agent:step`       | Iteration begins             | `currentIteration`                    |
| `agent:action`     | Performing an action         | `action`, `ref`, `value`              |
| `agent:reasoned`   | Agent’s reasoning            | `reasoning`                           |
| `agent:extracted`  | Data was extracted           | `extractedData`                       |
| `agent:waiting`    | Waiting for page load/action | `iterationId`, `seconds`, `timestamp` |

### Browser Events

| Event Type                    | Description              | Key Data Fields    |
| ----------------------------- | ------------------------ | ------------------ |
| `browser:navigated`           | Page navigation occurred | `url`, `title`     |
| `browser:action_started`      | Browser action starting  | `action`           |
| `browser:action_completed`    | Browser action finished  | `action`, `result` |
| `browser:screenshot_captured` | Screenshot taken         | `screenshotId`     |

### Interactive Events

These events are only emitted when `interactive: true` is set.

| Event Type                      | Description                             | Key Data Fields                          |
| ------------------------------- | --------------------------------------- | ---------------------------------------- |
| `interactive:form_data:request` | Agent needs user input for a form       | `requestId`, `fields`, `formDescription` |
| `interactive:form_data:error`   | Form validation failed after user input | `requestId`, `fields`, `fieldErrors`     |

### Stream Control Events

| Event Type | Description                                                                                                   |
| ---------- | ------------------------------------------------------------------------------------------------------------- |
| `complete` | Canonical final result. `data` carries `finalAnswer`, `stats`, `success`, and an optional structured `error`. |
| `done`     | Stream terminator, always sent last. Payload is empty (`{}`) today, reserved for future metadata.             |
| `error`    | Top-level runner crash. `data.error` is `{ code, message, timestamp }` with `success: false`.                 |

## Real-World Examples

### Example 1: Data Extraction with Navigation

- [TypeScript](#tab-panel-280)
- [JavaScript](#tab-panel-281)

```
console.log("Collecting GitHub trending repositories...\n");


const stream = await client.agent.automate({
  task: "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,
});


for await (const event of stream) {
  switch (event.event) {
    case "agent:status":
      console.log(`Status: ${event.data?.message}`);
      break;


    case "agent:action":
      console.log(`Action: ${event.data?.action}`);
      break;


    case "browser:navigated":
      console.log(`Navigated to: ${event.data?.url}`);
      break;


    case "agent:extracted":
      const extracted = event.data?.extractedData;
      console.log("Extracted data:", JSON.stringify(extracted, null, 2));
      break;


    case "task:completed":
      const result = event.data?.finalAnswer;
      console.log("\nAutomation completed!");
      console.log("Final result:", result);
      break;


    case "error":
      console.error("Error:", event.data?.error?.message);
      break;
  }
}
```

```
console.log("Collecting GitHub trending repositories...\n");


const stream = await client.agent.automate({
  task: "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,
});


for await (const event of stream) {
  switch (event.event) {
    case "agent:status":
      console.log(`Status: ${event.data?.message}`);
      break;


    case "agent:action":
      console.log(`Action: ${event.data?.action}`);
      break;


    case "browser:navigated":
      console.log(`Navigated to: ${event.data?.url}`);
      break;


    case "agent:extracted":
      const extracted = event.data?.extractedData;
      console.log("Extracted data:", JSON.stringify(extracted, null, 2));
      break;


    case "task:completed":
      const result = event.data?.finalAnswer;
      console.log("\nAutomation completed!");
      console.log("Final result:", result);
      break;


    case "error":
      console.error("Error:", event.data?.error?.message);
      break;
  }
}
```

### Example 2: Form Filling

- [TypeScript](#tab-panel-282)
- [JavaScript](#tab-panel-283)

```
console.log("Filling contact form...\n");


const formData = {
  name: "Alex Johnson",
  email: "alex@example.com",
  company: "Example Corp",
  message: "I am interested in learning more about your product offerings.",
};


const stream = await client.agent.automate({
  task: "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,
});


for await (const event of stream) {
  switch (event.event) {
    case "agent:action":
      const action = event.data?.action;
      const value = event.data?.value;
      console.log(`Action: ${action}${value ? ` (${value})` : ""}`);
      break;


    case "agent:status":
      console.log(`Status: ${event.data?.message}`);
      break;


    case "task:completed":
      console.log("\nForm submitted successfully!");
      const confirmation = event.data?.finalAnswer;
      console.log("Confirmation:", confirmation);
      break;


    case "error":
      console.error("Error submitting form:", event.data?.error?.message);
      break;
  }
}
```

```
console.log("Filling contact form...\n");


const formData = {
  name: "Alex Johnson",
  email: "alex@example.com",
  company: "Example Corp",
  message: "I am interested in learning more about your product offerings.",
};


const stream = await client.agent.automate({
  task: "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,
});


for await (const event of stream) {
  switch (event.event) {
    case "agent:action":
      const action = event.data?.action;
      const value = event.data?.value;
      console.log(`Action: ${action}${value ? ` (${value})` : ""}`);
      break;


    case "agent:status":
      console.log(`Status: ${event.data?.message}`);
      break;


    case "task:completed":
      console.log("\nForm submitted successfully!");
      const confirmation = event.data?.finalAnswer;
      console.log("Confirmation:", confirmation);
      break;


    case "error":
      console.error("Error submitting form:", event.data?.error?.message);
      break;
  }
}
```

### Example 3: Multi-Step Workflow

- [TypeScript](#tab-panel-284)
- [JavaScript](#tab-panel-285)

```
console.log("Starting product research workflow...\n");


const steps: string[] = [];
const extractedData: any[] = [];


const stream = await client.agent.automate({
  task: `
    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,
});


for await (const event of stream) {
  switch (event.event) {
    case "agent:step":
      const iteration = event.data?.currentIteration ?? 0;
      steps.push(`Step ${iteration + 1}`);
      console.log(`\nStep ${iteration + 1}`);
      break;


    case "agent:action":
      console.log(`  -> ${event.data?.action}`);
      break;


    case "agent:extracted":
      const data = event.data?.extractedData;
      extractedData.push(data);
      console.log("  -> Extracted:", data);
      break;


    case "task:completed":
      console.log("\nWorkflow completed!");
      console.log(`\nCompleted ${steps.length} steps`);


      const finalResult = event.data?.finalAnswer;
      console.log("\nFinal Results:");
      console.log(JSON.stringify(finalResult, null, 2));
      break;


    case "error":
      console.error("\nWorkflow failed:", event.data?.error?.message);
      break;
  }
}
```

```
console.log("Starting product research workflow...\n");


const steps = [];
const extractedData = [];


const stream = await client.agent.automate({
  task: `
    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,
});


for await (const event of stream) {
  switch (event.event) {
    case "agent:step":
      const iteration = event.data?.currentIteration ?? 0;
      steps.push(`Step ${iteration + 1}`);
      console.log(`\nStep ${iteration + 1}`);
      break;


    case "agent:action":
      console.log(`  -> ${event.data?.action}`);
      break;


    case "agent:extracted":
      const data = event.data?.extractedData;
      extractedData.push(data);
      console.log("  -> Extracted:", data);
      break;


    case "task:completed":
      console.log("\nWorkflow completed!");
      console.log(`\nCompleted ${steps.length} steps`);


      const finalResult = event.data?.finalAnswer;
      console.log("\nFinal Results:");
      console.log(JSON.stringify(finalResult, null, 2));
      break;


    case "error":
      console.error("\nWorkflow failed:", event.data?.error?.message);
      break;
  }
}
```

### Example 4: Progress Tracking with UI

Build a simple progress tracker:

- [TypeScript](#tab-panel-286)
- [JavaScript](#tab-panel-287)

```
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("\nComplete!");
  } else if (progress.error) {
    console.log(`\nError: ${progress.error}`);
  }
}


try {
  const stream = await client.agent.automate({
    task: "Find and extract the top 5 blog posts",
    url: "https://blog.example.com",
  });


  for await (const event of stream) {
    switch (event.event) {
      case "agent:status":
        progress.status = event.data?.message || "Processing...";
        break;


      case "agent:step":
        progress.currentStep = (event.data?.currentIteration ?? 0) + 1;
        break;


      case "agent:action":
        progress.lastAction = event.data?.action || "";
        break;


      case "task:completed":
        progress.isComplete = true;
        progress.status = "Completed";
        break;


      case "error":
        progress.error = event.data?.error?.message;
        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("\nComplete!");
  } else if (progress.error) {
    console.log(`\nError: ${progress.error}`);
  }
}


try {
  const stream = await client.agent.automate({
    task: "Find and extract the top 5 blog posts",
    url: "https://blog.example.com",
  });


  for await (const event of stream) {
    switch (event.event) {
      case "agent:status":
        progress.status = event.data?.message || "Processing...";
        break;


      case "agent:step":
        progress.currentStep = (event.data?.currentIteration ?? 0) + 1;
        break;


      case "agent:action":
        progress.lastAction = event.data?.action || "";
        break;


      case "task:completed":
        progress.isComplete = true;
        progress.status = "Completed";
        break;


      case "error":
        progress.error = event.data?.error?.message;
        break;
    }


    displayProgress(progress);
  }
} catch (error) {
  progress.error = error.message;
  displayProgress(progress);
}
```

## Working with Event Data

Each event includes an `event` property and a `data` object:

- [TypeScript](#tab-panel-288)
- [JavaScript](#tab-panel-289)

```
const stream = await client.agent.automate({
  task: "Find products",
  url: "https://example.com",
});


for await (const event of stream) {
  // Access event type
  console.log("Event type:", event.event);


  // Access data fields directly using optional chaining
  const message = event.data?.message;
  const step = event.data?.currentIteration ?? 0;


  // Access nested data
  if (event.data?.extractedData) {
    const data = event.data.extractedData;
    // Process extracted data
  }


  // Log all event data
  console.log("Event data:", event.data);
}
```

```
const stream = await client.agent.automate({
  task: "Find products",
  url: "https://example.com",
});


for await (const event of stream) {
  // Access event type
  console.log("Event type:", event.event);


  // Access data fields directly using optional chaining
  const message = event.data?.message;
  const step = event.data?.currentIteration ?? 0;


  // Access nested data
  if (event.data?.extractedData) {
    const data = event.data.extractedData;
    // Process extracted data
  }


  // Log all event data
  console.log("Event data:", event.data);
}
```

## Options Reference

### AutomateOptions

| Option                  | Type                  | Default | Description                                                                                                                                                                                                    |
| ----------------------- | --------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `task`                  | `string`              | -       | The task description in natural language                                                                                                                                                                       |
| `url`                   | `string`              | -       | Starting URL for the automation                                                                                                                                                                                |
| `data`                  | `unknown`             | -       | Context data (e.g., form fields to fill); object-shaped in practice                                                                                                                                            |
| `geo_target`            | `{ country: string }` | -       | Geotargeting parameters for region-specific browsing (e.g., `{ country: 'US' }`). Snake\_case is intentional. This is the one automate option that is not camelCase, so a `geoTarget` key is silently ignored. |
| `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)                                                                                                                                                                |
| `interactive`           | `boolean`             | `false` | Enable interactive mode for human-in-the-loop form filling                                                                                                                                                     |

## Interactive Mode

Interactive mode allows the automation agent to pause and request user input when it encounters forms requiring personal data. Enable it by passing `interactive: true`:

- [TypeScript](#tab-panel-290)
- [JavaScript](#tab-panel-291)

```
import Tabstack from "@tabstack/sdk";
import * as readline from "readline";


const client = new Tabstack();


// Helper to prompt user for input
function prompt(question: string): Promise<string> {
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      rl.close();
      resolve(answer);
    });
  });
}


const stream = await client.agent.automate({
  task: "Sign up for the newsletter",
  url: "https://example.com",
  interactive: true,
});


for await (const event of stream) {
  // The agent requests form data when it encounters a form
  if (event.event === "interactive:form_data:request") {
    const { requestId, fields } = event.data;


    const fieldValues = [];
    for (const field of fields) {
      const label = field.label || "Field";
      const required = field.required ? "*" : "";
      const value = await prompt(`  ${label}${required}: `);
      fieldValues.push({ ref: field.ref, value });
    }


    // Submit values back to resume the task
    await client.agent.automateInput(requestId, { fields: fieldValues });
  }


  // Handle validation errors with corrected values
  else if (event.event === "interactive:form_data:error") {
    const { requestId, fields, fieldErrors } = event.data;


    const fieldValues = [];
    for (const field of fields) {
      const error = fieldErrors[field.ref];
      const label = field.label || "Field";
      const suffix = error ? ` (${error})` : "";
      const value = await prompt(`  ${label}${suffix}: `);
      fieldValues.push({ ref: field.ref, value });
    }


    await client.agent.automateInput(requestId, { fields: fieldValues });
  } else if (event.event === "complete") {
    console.log("Done:", event.data);
  }
}
```

```
const Tabstack = require("@tabstack/sdk").default;
const readline = require("readline");


const client = new Tabstack();


// Helper to prompt user for input
function prompt(question) {
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      rl.close();
      resolve(answer);
    });
  });
}


const stream = await client.agent.automate({
  task: "Sign up for the newsletter",
  url: "https://example.com",
  interactive: true,
});


for await (const event of stream) {
  if (event.event === "interactive:form_data:request") {
    const { requestId, fields } = event.data;


    const fieldValues = [];
    for (const field of fields) {
      const label = field.label || "Field";
      const required = field.required ? "*" : "";
      const value = await prompt(`  ${label}${required}: `);
      fieldValues.push({ ref: field.ref, value });
    }


    await client.agent.automateInput(requestId, { fields: fieldValues });
  } else if (event.event === "interactive:form_data:error") {
    const { requestId, fields, fieldErrors } = event.data;


    const fieldValues = [];
    for (const field of fields) {
      const error = fieldErrors[field.ref];
      const label = field.label || "Field";
      const suffix = error ? ` (${error})` : "";
      const value = await prompt(`  ${label}${suffix}: `);
      fieldValues.push({ ref: field.ref, value });
    }


    await client.agent.automateInput(requestId, { fields: fieldValues });
  } else if (event.event === "complete") {
    console.log("Done:", event.data);
  }
}
```

To cancel an interactive request instead of providing data:

```
await client.agent.automateInput(requestId, { cancelled: true });
```

For a complete guide, see [Interactive Mode](/guides/interactive-mode/index.md).

## 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:

```
const stream = await client.agent.automate({
  task: "Find products",
  url: "https://example.com",
});


for await (const event of stream) {
  switch (event.event) {
    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 {
  // Pass the signal so the timeout actually cancels the underlying request.
  const stream = await client.agent.automate(
    {
      task: "Complex task",
      url: "https://example.com",
    },
    { signal: controller.signal },
  );


  for await (const event of stream) {
    // Handle events (see the examples above)
    console.log(event.event);
  }


  // The SDK's stream iterator swallows abort errors, so on timeout the loop
  // just ends and nothing throws. Detect the timeout afterward.
  if (controller.signal.aborted) {
    console.log("Automation timed out");
  }
} finally {
  clearTimeout(timeoutId);
}
```

### 6. Log Important Events

Keep track of the automation flow:

```
const log: string[] = [];


const stream = await client.agent.automate({
  task: "Find products",
  url: "https://example.com",
});


for await (const event of stream) {
  const logEntry = `[${new Date().toISOString()}] ${event.event}: ${JSON.stringify(event.data)}`;
  log.push(logEntry);


  if (event.event === "task:completed" || event.event === "error") {
    // Save log to file or database
    await saveLog(log);
  }
}
```

## Error Handling

Always wrap automation in try-catch blocks:

- [TypeScript](#tab-panel-292)
- [JavaScript](#tab-panel-293)

```
try {
  const stream = await client.agent.automate({
    task: "Find products",
    url: "https://example.com",
  });


  for await (const event of stream) {
    if (event.event === "error") {
      const error = event.data?.error?.message;
      console.error("Automation error:", error);
      // Handle gracefully
      break;
    }


    if (event.event === "task:completed") {
      // Success
    }
  }
} catch (error) {
  console.error("Fatal error:", error.message);
  // Cleanup and notify
}
```

```
try {
  const stream = await client.agent.automate({
    task: "Find products",
    url: "https://example.com",
  });


  for await (const event of stream) {
    if (event.event === "error") {
      const error = event.data?.error?.message;
      console.error("Automation error:", error);
      // Handle gracefully
      break;
    }


    if (event.event === "task:completed") {
      // Success
    }
  }
} catch (error) {
  console.error("Fatal error:", error.message);
  // Cleanup and notify
}
```

## Next Steps

- **[Error Handling](./error-handling)**: Build robust applications with comprehensive error handling
- **[Generate Features](./generate)**: Discover AI-powered content transformation
- **[REST API Reference](/api/index.md)**: See the underlying REST API endpoint
