Introduction

What is Witrium?

Witrium is a no-code platform that lets you build automations on the web without writing a single line of code. It provides a simple way to create, run, and manage browser automations that can interact with any website.

Think of Witrium as your personal robot that can navigate the web, perform tasks, and extract information - all following your natural language instructions.

Key Features

  • Natural language instructions - no coding required
  • Visual workflow builder with real-time preview
  • Fully managed browser infrastructure
  • Self-healing automations that adapt to website changes
  • Advanced stealth mode to avoid detection
  • API endpoints to run workflows programmatically

Core Concepts

  1. Workflows

    A sequence of instructions that define a specific automation task, like scraping data from a website or filling out a form.

  2. Instructions

    Natural language commands that tell Witrium what to do, like "click the login button" or "extract the product prices".

  3. Build Sessions

    Interactive sessions where you build and test your workflows step by step, with a live browser preview.

  4. Workflow Runs

    Executions of your workflows, either manually triggered via the UI or the API, or scheduled, with detailed results for each step.

Who is it for

Developers

Tired of maintaining brittle Selenium or Playwright scripts? Witrium helps you:

  • Reduce maintenance overhead of automation scripts
  • Eliminate the need for CSS selectors or XPaths
  • Create API endpoints from any website
  • Focus on your core application, not browser automation

Business Users

Need to automate repetitive web tasks but don't know how to code? Witrium enables you to:

  • Automate data collection from websites
  • Set up form submissions and repetitive tasks
  • Monitor websites for changes or updates
  • Create workflows with simple English instructions

QA Engineers

Looking for simpler ways to test web applications? Witrium helps you:

  • Create test scenarios without complicated test frameworks
  • Build resilient end-to-end tests
  • Schedule automated testing runs
  • Get detailed results for each step of the test

API Builders

Need to integrate with websites that don't provide APIs? With Witrium you can:

  • Transform any website into an API endpoint
  • Extract structured data from unstructured web pages
  • Integrate web data into your applications
  • Build middleware between web-only services

Workflow Builder

Understanding Workflows

A workflow in Witrium is a sequence of instructions that automate interactions with a website. Every workflow starts with a URL and then contains the steps needed to navigate and interact with that site.

Workflows can be as simple as visiting a page and extracting some text, or as complex as logging in, filling out forms, and performing multi-step operations.

Creating a Workflow

1. Start with a name and description

Give your workflow a clear name and description that indicates what it does. This helps you identify it later when you have multiple workflows.

2. Set the starting URL

Enter the URL of the website you want to start your automation with. This could be the homepage or a specific sub-page. URL parameters are also allowed. This instruction will become the first instruction in your workflow as: "go to [URL]"

3. Choose a browser provider (optional)

We offer a list of browser providers, each with unique fingerprinting and stealth strategies. While the default "any" option suffices for most cases, you may need to experiment with different providers for websites with robust bot detection. Your selection will be saved as the default for this workflow.

4. Enable stealth mode (optional)

For websites with advanced bot detection, enable stealth mode. This feature utilizes residential proxies for enhanced stealth capabilities. Your selection here will become the default for future runs of this workflow.

5. Edit your workflow anytime

You can edit or add instructions to your workflow—either at the end or in the middle of the sequence—even when a build session is not active.

Workflow Structure

A typical workflow in Witrium follows this structure:

  1. Starting URL: "go to https://example.com"

    This is automatically added as the first instruction

  2. Navigation instructions: "click on the login button"

    Instructions to navigate within the website

  3. Interaction instructions: "type 'username' in the username field"

    Instructions to interact with form elements and inputs

  4. Extraction instructions: "extract all product prices"

    Instructions to extract data from the page

Each instruction is executed in order, and you can test them individually in their intended sequence during a build session to ensure they work correctly.

Best Practices

  • Be specific: Instead of "click the button", use "click the Submit button"
  • Break down complex tasks: Use multiple simple instructions instead of one complex instruction
  • Use descriptive text: Witrium can identify elements by their visible text, so use that to your advantage
  • Test as you build: Use build sessions to verify each instruction works correctly
  • Add wait times: If a page is loading dynamic content, add "wait for 3 seconds" instructions
witrium.com/workflows
Workflow builder interface

The Workflow Builder interface allows you to create and edit instructions

Build Sessions

What is a Build Session?

A Build Session is an interactive environment where you can test your workflow instructions in real-time. It opens a live browser instance where you can see your instructions being executed step by step.

Think of it as a playground where you can experiment with instructions, see their effects immediately, and refine your workflow until it works perfectly.

Starting a Build Session

To start a build session, follow these steps:

  1. Navigate to your workflow

    Open the workflow you want to build or refine

  2. Check your target URL

    Verify that the starting URL is correct

  3. Select your browser provider (optional)

    Choose from available browser providers if you have specific requirements

  4. Configure stealth settings (optional)

    Enable stealth mode if you need protection against bot detection

  5. Using Existing Sessions (optional)

    If you have previously run any workflow and saved (preserved) a browser session, you can select one (or more) to resume from that state. This is particularly useful for workflows that require login or other setup steps. See the Session Management section for detailed information on creating and managing sessions.

  6. Click "Start Build Session"

    This will open a live browser instance in the cloud and livestream it in the window on the right.

During a Build Session

Once your build session is active, you can interactively build and test your workflow. Add your first instruction and click the play button to see it execute in the live browser on the right. This allows you to verify each step in real-time.

While the session is active, you can:

  • Add new instructions to your workflow
  • Edit existing instructions to refine them
  • Play individual instructions to test them one by one
  • View results of each instruction, including extracted data
  • Monitor the live browser to see how your instructions interact with the website

Handling Failed Instructions

If an instruction fails during a build session, the browser state may become unrecoverable. It's often best to end the session and start a new one to ensure a clean testing environment.

Ending a Build Session

After you are done building the automation, click on "End Build Session" to terminate the browser instance and end your build session. Your workflow, with all its instructions, is saved automatically.

Your workflow is now ready to be run as a complete sequence, either manually or via the API.

witrium.com/workflows/build-session
Build session interface

The Build Session interface with live browser preview and instruction controls

Working with Instructions

Understanding Instructions

Instructions are natural language commands that tell Witrium what to do in a browser. They're written in plain English, so you don't need to learn a special syntax or programming language.

Witrium's AI understands your intent and translates your instructions into browser actions, handling the complexity of finding elements and interacting with them.

Instruction Types

Adding Instructions

Adding instructions to your workflow is simple:

  1. Start a build session if you haven't already
  2. Click the "Add Instruction" button at the bottom of your workflow
  3. Type your instruction in plain English
  4. Save your instruction by clicking the save button

Using Arguments in Instructions

You can add dynamic arguments to your instructions using curly braces:

{{argument_name}}

For secret values, use the $ prefix:

{{$argument_name}}
Secret Arguments Benefits:
  • Temporarily stored in an encrypted vault for the duration of the workflow run
  • Automatically deleted after the workflow run completion
  • Secret values are never sent to the underlying LLM model provider
  • Displayed as password fields (masked input) in the workflow builder

Examples:

type "{{email}}" in the email field

type "{{$password}}" in the password field

type "{{first_name}}" in the first name field

extract all product information for the products with price greater than {{price}}

When running the workflow from the dashboard, you'll be prompted to provide values for these arguments. When using the API, pass arguments as a JSON object in the request body under the "args" key.

Testing Instructions

During a build session, you can test each instruction individually in their intended sequence to make sure it works as expected:

  1. Find the first instruction of the workflow you want to test
  2. Click the Play button next to that instruction
  3. Watch the browser as the instruction is executed
  4. Check the results to see if the instruction succeeded
  5. Go to the next instruction and repeat the process

Instructions can have five execution states:

  • Pending: Not yet executed
  • Running: Currently being executed
  • Completed: Successfully executed
  • Failed: Execution failed
  • Cancelled: Execution cancelled

Managing Instructions

You can manage your instructions with these actions:

Edit an instruction

Click the edit button next to an instruction to modify its text. Save your changes when done.

Delete an instruction

Click the delete button next to an instruction to remove it from the workflow.

Instruction order

Instructions are executed in the order they appear in your workflow. The first instruction is always the URL instruction.

Session Management

What is Session Management?

Session management allows you to save and reuse browser states across workflow runs. This includes cookies, authentication tokens, local storage, and other browser data that maintains your logged-in status or application state.

This is particularly powerful for websites that require authentication, as you can log in once and reuse that authenticated session across multiple workflow executions.

Why Use Session Management?

Session management solves several common challenges in web automation:

Authentication Workflows

  • Avoid re-logging in for each workflow run
  • Handle multi-factor authentication once
  • Bypass CAPTCHA challenges
  • Maintain session across different workflows

Multi-Step Processes

  • Break complex workflows into smaller parts
  • Start from specific application states
  • Share sessions between different workflows
  • Resume workflows from saved checkpoints

Creating Authentication Workflows

The most common use case for session management is handling authentication. Here's the recommended pattern:

1. Create a Login Workflow

Create a separate workflow dedicated to authentication:

  1. Set target URL to the login page (e.g., https://example.com/login)
  2. Add instruction: "type {{email}} in the email field"
  3. Add instruction: "type {{$password}} in the password field"
  4. Add instruction: "click the sign in button"
  5. Add instruction: "wait 10 seconds" (for redirects and page load)

2. Run with Session Preservation

When running your login workflow:

  1. Click "Run Workflow"
  2. Enter your credentials in the arguments
  3. Go to the "Session Management" tab
  4. Toggle "Preserve session" to ON
  5. Enter a session name (e.g., "linkedin-login-session")
  6. Click "Start Run"

3. Create Data Extraction Workflows

Create separate workflows that use the saved session:

  1. Set target URL to the authenticated page you want to extract from
  2. Add instruction: "wait 10 seconds" (for page load stabilization)
  3. Add your data extraction instructions
  4. When running, select "Use existing session" and choose your saved session

Managing Browser Sessions

Session Storage

Sessions are securely stored in an encrypted vault. The data stored in sessions may include:

  • Cookies and authentication tokens
  • Local storage and session storage data
  • Browser cache and other state information

Session Management Dashboard

You can manage all your saved sessions at:

https://witrium.com/settings?tab=browser-sessions

Session Expiration

Sessions may expire based on the website's authentication policies. When a session expires, you'll need to run your login workflow again with the same session name to refresh the session.

Using Sessions via API

You can specify which sessions to use when running workflows via the API:

API Request with Session

{
  "args": {
    "parameter1": "value1"
  },
  "use_states": ["session-name"]
}

Python SDK with Sessions

from witrium.client import SyncWitriumClient

with SyncWitriumClient(api_token=API_TOKEN) as client:
    result = client.run_workflow_and_wait(
        workflow_id=WORKFLOW_ID,
        args={"search_term": "vacuum cleaners"},
        use_states=["linkedin-login-session"]
    )

Advanced Session Patterns

Multiple Account Support

Create separate sessions for different accounts:

  • • linkedin-personal-account
  • • linkedin-company-account
  • • twitter-marketing-account

Session Refresh Strategy

Implement automatic session refresh by checking for authentication failures and re-running your login workflow when needed.

Session Isolation

Each saved session is completely isolated, so you can maintain multiple authenticated sessions for the same website using different accounts.

Running Workflows

Running a Workflow

Once you've created and tested your workflow, you can run it in two main ways:

1. From the UI

Navigate to your workflow and click the "Run Workflow" button. You'll be prompted to enter any required parameters.

2. Via the API

Trigger your workflow programmatically using an API call. This is ideal for automation and integration with other systems.

Monitoring Runs

When you run a workflow, Witrium provides detailed information about the run:

  • Run status: Pending, Running, Completed, or Failed
  • Execution progress: Which instructions have been completed
  • Results: Data extracted by the workflow
  • Error messages: If something went wrong
  • Screenshots: Visual record of what happened

Workflow Parameters

When running a workflow, you may need to provide values for parameters defined in your instructions:

Required Parameters

All parameters defined in the workflow must be provided for the workflow to run.

The Starting URL Parameter

You can optionally override the starting URL when running a workflow.

API Integration

API Overview

Witrium provides a REST API that lets you run workflows programmatically and retrieve their results. This makes it easy to integrate browser automation into your existing systems.

Every workflow you create automatically has an API endpoint that you can call to execute it.

Running a Workflow via API

Endpoint

POST https://api.witrium.com/v1/workflows/{workflow_id}/run

Authentication

Include your API key in the request headers:

X-Witrium-Key: YOUR_API_KEY

Request Body

Send a JSON object containing the workflow configuration:

{
  "args": {
    "url": "https://example.com",          // Optional: override the starting URL
    "parameter1": "value1",		// Optional: Regular parameter with default value
    "parameter2": "value2",		// Optional: Regular parameter with default value
    "$secret_param1": "sensitive_value1"  // Secret argument with $ prefix
	"$secret_param2": "sensitive_value2"  // Secret argument with $ prefix
  },
  "use_states": ["session-name"],       // Optional
  "preserve_state": "state-name",             // Optional
  "no_intelligence": false,       // Optional
  "record_session": false,         // Optional
  "keep_session_alive": false,     // Optional
  "use_existing_session": "run-id",    // Optional
}
Key Parameters:
  • args: Workflow arguments including secret values
  • use_states: Array of session names to load
  • preserve_state: Save browser state after completion, value is the name you want to use to save the state
  • no_intelligence: If true, the workflow will not use AI assistance on every instruction during execution
  • record_session: If true, a video of the session will be recorded after completion and can be accessed on the workflow run details page
  • keep_session_alive: If true, the browser will not be terminated after completion of the workflow run
  • use_existing_session: If you want to use an existing browser that was kept alive after completion of the workflow run, you can specify the id of the run here who's kept alive browser you want to use

Response

The API returns a response containing the run ID:

{
  "workflow_id": "workflow_id",
  "run_id": "run_id",
  "status": "submitted"
}

Retrieving Results

Results Endpoint

GET https://api.witrium.com/v1/runs/{run_id}/results

Authentication

X-Witrium-Key: YOUR_API_KEY

Response

The response includes the current status, progress, and results if available:

{
  "workflow_id": "workflow_id",
  "run_id": "run_id",
  "status": "running", // "pending" | "running" | "completed" | "failed" | "cancelled"
  "started_at": "2023-07-01T12:00:00Z",
  "completed_at": null,
  "message": "Workflow is executing",
  "executions": [
    {
      "status": "completed",
      "instruction_order": 1,
      "instruction": "Go to the homepage",
      "result": { "some_data": "value" },
      "result_format": "json",
	  "error_message": null
    },
    {
      "status": "running",
      "instruction_order": 2,
      "instruction": "Fill in the form",
      "result": null,
	  "error_message": null
    }
  ],
  "result": null,
  "result_format": null,
  "error_message": null
}

Polling for Results

Workflows execute asynchronously in the background, so you'll need to poll the results endpoint to check the status:

  1. Run the workflow and get the run_id
  2. Poll the results endpoint at reasonable intervals (e.g., every 5-10 seconds)
  3. Check the status field in the response
  4. Continue polling until status is "completed" or "failed"
  5. Process the results once the workflow has finished

Handling Long-Running Workflows

For workflows that may take a long time to execute, consider implementing exponential backoff in your polling logic to avoid excessive API calls.

Practical API Examples

1. Login and Data Extraction

Complete example of authenticated workflow execution:

# Step 1: Login and preserve session
curl -X POST \
  -H "X-Witrium-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  "https://api.witrium.com/v1/workflows/LOGIN_WORKFLOW_ID/run" \
  -d '{
    "args": {
      "email": "user@example.com",
      "$password": "secret_password"
    },
    "preserve_state": "linkedin-session"
  }'

# Step 2: Use session for data extraction
curl -X POST \
  -H "X-Witrium-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  "https://api.witrium.com/v1/workflows/EXTRACTION_WORKFLOW_ID/run" \
  -d '{
    "use_states": ["linkedin-session"]
  }'

2. Parallel Data Collection

Run multiple workflows concurrently for different pages:

# Bash script for parallel execution
#!/bin/bash

WORKFLOW_ID="YOUR_WORKFLOW_ID"
API_KEY="YOUR_API_KEY"

# Function to run single page
run_page() {
  local page=$1
  local url="https://example.com/search?page=$page"
  
  curl -X POST \
    -H "X-Witrium-Key: $API_KEY" \
    -H "Content-Type: application/json" \
    "https://api.witrium.com/v1/workflows/$WORKFLOW_ID/run" \
    -d "{\"args\": {\"url\": \"$url\"}}" \
    -s | jq -r '.run_id'
}

# Launch multiple pages in parallel
for i in {1..10}; do
  run_page $i &
done

wait  # Wait for all background jobs to complete

Integration Patterns

Data Collection Pipeline

Schedule workflows to collect data automatically, process results, and store them in your database. Use webhooks or polling to trigger downstream processing when workflows complete.

Integration Testing

Integrate workflows into your CI/CD pipeline to verify that your web applications are working correctly. Use different browser sessions to test various user scenarios.

Data Synchronization

Create workflows that extract data from one system and submit it to another, keeping data in sync between platforms that don't have direct API integrations.

Monitoring & Alerting

Set up workflows to monitor websites for changes, price updates, or availability. Combine with notification systems to alert when specific conditions are met.

Client SDKs

What are Client SDKs?

Client SDKs provide a more convenient way to interact with Witrium's API from your programming language of choice. Instead of making raw HTTP requests, you can use native language constructs and helper methods that handle the complexity for you.

Client SDKs offer benefits like automatic polling, type safety, error handling, and a more intuitive developer experience compared to using the REST API directly.

Python Client

Our official Python client provides a simple, Pythonic interface to the Witrium API. It includes features like automatic polling, context managers, and proper error handling.

Installation

pip install witrium

Quick Start

from witrium.client import SyncWitriumClient

with SyncWitriumClient(api_token="your-api-token") as client:
    # Simple workflow execution with automatic waiting
    result = client.run_workflow_and_wait(
        workflow_id="workflow-id",
        args={"key": "value"}
    )
    print(result.result)

Advanced: Parallel Processing

For high-throughput scenarios, you can run multiple workflows in parallel:

import csv
from concurrent.futures import ThreadPoolExecutor, as_completed
from witrium.client import SyncWitriumClient

def run_single_page(client, page_num):
    """Run workflow for a single page"""
    result = client.run_workflow_and_wait(
        workflow_id="your-workflow-id",
        args={"page": page_num}
    )
    return result.result if result.status == "COMPLETED" else None

# Run multiple pages in parallel
with SyncWitriumClient(api_token="your-api-token") as client:
    pages = range(1, 11)  # Pages 1-10
    results = []
    
    with ThreadPoolExecutor(max_workers=4) as executor:
        futures = {executor.submit(run_single_page, client, p): p for p in pages}
        
        for future in as_completed(futures):
            page = futures[future]
            try:
                result = future.result()
                if result:
                    results.append(result)
                    print(f"Page {page} completed")
            except Exception as e:
                print(f"Page {page} failed: {e}")
    
    print(f"Collected {len(results)} results")

Error Handling & Retries

Robust error handling with automatic retries:

import time
from witrium.client import SyncWitriumClient, WorkflowRunStatus

def run_with_retry(client, workflow_id, args, max_retries=3):
    """Run workflow with exponential backoff retry"""
    for attempt in range(max_retries):
        try:
            result = client.run_workflow_and_wait(
                workflow_id=workflow_id,
                args=args
            )
            
            if result.status == WorkflowRunStatus.COMPLETED:
                return result.result
            else:
                raise Exception(f"Workflow failed: {result.error_message}")
                
        except Exception as e:
            print(f"Attempt {attempt + 1} failed: {e}")
            if attempt == max_retries - 1:
                raise e
            time.sleep(2 ** attempt)  # Exponential backoff

Data Processing Pipeline

Complete example for data collection and processing:

import csv
import os
from urllib.parse import quote_plus
from witrium.client import SyncWitriumClient

def save_to_csv(data, filename="results.csv"):
    """Save extracted data to CSV"""
    is_new = not os.path.exists(filename)
    with open(filename, "a", newline="", encoding="utf-8") as f:
        if data and len(data) > 0:
            writer = csv.DictWriter(f, fieldnames=data[0].keys())
            if is_new:
                writer.writeheader()
            writer.writerows(data)

def scrape_search_results(search_term, max_pages=10):
    """Scrape search results across multiple pages"""
    API_TOKEN = "your-api-token"
    WORKFLOW_ID = "your-workflow-id"
    
    with SyncWitriumClient(api_token=API_TOKEN) as client:
        all_results = []
        
        for page in range(1, max_pages + 1):
            try:
                # Dynamic URL construction
                search_url = f"https://example.com/search?q={quote_plus(search_term)}&page={page}"
                
                result = client.run_workflow_and_wait(
                    workflow_id=WORKFLOW_ID,
                    args={"url": search_url}
                )
                
                if result.status == "COMPLETED" and result.result:
                    items = result.result.get("items", [])
                    # Add page metadata
                    for item in items:
                        item["page"] = page
                        item["search_term"] = search_term
                    
                    all_results.extend(items)
                    save_to_csv(items, f"{search_term}_results.csv")
                    print(f"Page {page}: {len(items)} items")
                
            except Exception as e:
                print(f"Page {page} failed: {e}")
        
        return all_results

# Usage
results = scrape_search_results("vacuum cleaners", max_pages=5)
print(f"Total items collected: {len(results)}")

Key Features

  • Automatic polling: Built-in methods to wait for workflow completion
  • Context managers: Proper resource management with Python's "with" statement
  • Type hints: Full type annotation support for better IDE experience
  • Error handling: Structured exceptions for different error conditions

Documentation & Source

For full documentation, advanced patterns, and source code, visit the witrium-py GitHub repository.

Why Use Client SDKs?

Client SDKs provide several advantages over using the REST API directly:

Developer Experience

  • Native language constructs and idioms
  • Built-in documentation and examples
  • IDE autocompletion and type checking

Functionality

  • Automatic polling and status checking
  • Structured error handling and retries
  • Helper methods for common operations

Choosing Between REST API and SDKs

Use the REST API when:

  • Working with languages that don't have an official SDK
  • You need maximum control over HTTP requests and responses
  • Building a custom SDK or wrapper for your specific needs

Use Client SDKs when:

  • You want a simpler, more intuitive development experience
  • You need automatic polling and status management
  • You prefer native language constructs and type safety

More Languages Coming Soon

We're actively working on client SDKs for additional programming languages. If you'd like to see support for a specific language, please let us know through our support channels.

In the meantime, you can always use our REST API from any language that supports HTTP requests, or contribute a community SDK for your preferred language.

Advanced Usage

URL Parameters & Dynamic Workflows

Create flexible workflows that can handle different URLs and parameters dynamically. This is particularly useful for pagination, search terms, and content variations.

Dynamic URL Construction

Override the workflow's entire target URL at runtime:

"url": "https://example.com/search?q=laptops"
"url": "https://example.com/search?q=vacuum+cleaners"

Pagination Strategies

Instead of navigating through pagination manually, change URL parameters:

  • Run the same workflow multiple times with different page numbers
    "url": "https://example.com/search?q=laptops&page=3"
    "url": "https://example.com/search?q=laptops&page=6"
  • Use parallel execution to process multiple pages simultaneously
  • Aggregate results from all pages into a single dataset

Stealth Mode

Stealth mode helps you avoid detection by websites that use anti-bot measures. It works by:

  • Using proxy servers to mask your IP address
  • Emulating human-like browser fingerprints
  • Adding random delays and mouse movements

Enable stealth mode in the workflow settings when working with websites that have strict bot detection, or when you need to avoid IP-based rate limiting.

Performance Optimization

For optimal performance with Witrium workflows:

  • Make instructions atomic and granular: Each instruction should be as specific and singular as possible, leaving no room for misinterpretation or confusion by the AI
  • Use specific selectors: Be precise in your instructions to help the AI identify elements quickly
  • Add strategic waits: Use "wait for" instructions for dynamic content, but avoid unnecessary waits
  • Extract only needed data: Be specific about what data to extract rather than grabbing everything

Error Handling

Witrium provides several ways to handle errors in your workflows:

Error Messages

When an instruction fails, Witrium provides detailed error messages explaining what went wrong.

Screenshots

Each execution includes screenshots at each step, which can help diagnose issues visually.

Resilient Instructions

Try to make your instructions resilient to small changes in the website. For example, "click the login button" is more resilient than "click the button at coordinates X,Y" for a website with dynamic content.

Advanced Instruction Patterns

Here are some advanced instruction patterns to handle complex scenarios:

Conditional Actions

if there is a popup, click the close button

Data Extraction with Filters

extract all prices greater than $100 from the products table

Complex Navigation

click the 3 dots menu in the row containing "Project Alpha"

Regex-based Extraction

extract all email addresses from the contact page
witrium.com/advanced-usage
Advanced usage example

Advanced workflows can handle complex interactions and data extraction