Skip to main content
Build dynamic workflows by chaining single actions together programmatically. This approach gives you full control over execution flow with your own code.

Quick Start

The basic workflow involves three steps:
  1. Create a session to maintain browser state
  2. Execute actions using the session
  3. Terminate the session when done

Your First Workflow

Here’s a simple example that creates a calendar meeting:
from dari import Dari

client = Dari(api_key="YOUR_API_KEY")

# Step 1: Create a session
session = client.create_session(
    screen_config={"width": 1440, "height": 900},
    ttl=3600  # 1 hour
)

session_id = session["session_id"]

try:
    # Step 2: Navigate to the website
    result1 = client.run_single_action(
        action="Navigate to Google Calendar",
        session_id=session_id,
        id="nav-to-calendar"
    )
    print(f"Step 1: {result1['result']}")

    # Step 3: Create a meeting
    result2 = client.run_single_action(
        action="Create a meeting called {{meeting_title}} for {{date}} at 3pm",
        session_id=session_id,
        id="create-meeting",
        variables={
            "meeting_title": "Q1 Planning Meeting",
            "date": "tomorrow"
        }
    )
    print(f"Step 2: {result2['result']}")

    # Step 4: Verify the meeting was created
    result3 = client.run_single_action(
        action="Check if the meeting '{{meeting_title}}' appears on the calendar",
        session_id=session_id,
        id="verify-meeting",
        variables={"meeting_title": "Q1 Planning Meeting"}
    )
    print(f"Step 3: {result3['result']}")

finally:
    # Step 5: Clean up the session
    client.terminate_session(session_id)
    print("Session terminated")

Understanding Sessions

Sessions maintain browser state across multiple actions:
  • Screen config: Set viewport dimensions
  • TTL: Session expires after this duration (in seconds)
  • Session ID: Use the same ID to chain actions together
# Create a session
session = client.create_session(
    screen_config={"width": 1440, "height": 900},
    ttl=3600  # Session lasts 1 hour
)

# The session_id is used for all subsequent actions
session_id = session["session_id"]
Always terminate sessions when done to free up resources and avoid unnecessary charges.

Using Variables

Variables let you pass dynamic values to your actions:
result = client.run_single_action(
    action="Search for {{product}} and add to cart",
    session_id=session_id,
    id="search-and-add",
    variables={
        "product": "wireless headphones"
    }
)
Variables are replaced at runtime using the {{variable_name}} syntax.

Action Results

Each action returns a result object:
result = client.run_single_action(
    action="Click the login button",
    session_id=session_id,
    id="click-login"
)

# Access the result
print(result["success"])  # True/False
print(result["result"])   # Description of what happened
print(result["credits"])  # Credits used

Sequential Actions

Chain actions together by using the same session:
session = client.create_session(
    screen_config={"width": 1440, "height": 900},
    ttl=3600
)

session_id = session["session_id"]

try:
    # Action 1
    client.run_single_action(
        action="Navigate to example.com",
        session_id=session_id,
        id="step-1"
    )

    # Action 2 (uses browser state from Action 1)
    client.run_single_action(
        action="Click the login button",
        session_id=session_id,
        id="step-2"
    )

    # Action 3 (uses browser state from Action 2)
    client.run_single_action(
        action="Enter email [email protected]",
        session_id=session_id,
        id="step-3"
    )

finally:
    client.terminate_session(session_id)

Best Practices

Ensure sessions are terminated even if errors occur:
try:
    # Your actions here
    pass
finally:
    client.terminate_session(session_id)
Give each action a unique, descriptive ID for easier debugging:
id="nav-to-dashboard"  # Good
id="action1"           # Bad
Short workflows: 300s (5 min) Medium workflows: 1800s (30 min) Long workflows: 3600s (1 hour)
Always check if actions succeeded:
result = client.run_single_action(...)
if not result.get("success"):
    print(f"Action failed: {result.get('error')}")

Advantages

Full Control

Complete programmatic control over execution flow and logic

Dynamic Logic

Make decisions at runtime based on previous action results

Easy Integration

Seamlessly integrate into existing codebases and applications

No Pre-Definition

Build workflows on-the-fly without pre-configuring in the dashboard

When to Use Programmatic Actions

Use programmatic actions when you need:
  • Dynamic decision-making based on runtime data
  • Complex conditional logic that can’t be predefined
  • Integration with existing application code
  • Version control of your workflows in Git
  • Custom error handling and retry logic
For stable, repeatable workflows that don’t need runtime decisions, consider using the Visual Workflow Builder instead.

Next Steps