Side-by-side comparison of Browser-use and WebRun showing migration path and performance improvements

If you've been using Browser-use for AI-powered browser automation, you already understand the power of letting language models control web browsers. WebRun takes that same paradigm and supercharges it with real-time performance, built-in human-in-the-loop guardrails, and a flexible API that works however your stack needs it to.

The best part? Migrating takes about five minutes.

Why Teams Are Making the Switch

Before we dive into code, here's what's driving the migration:

FeatureBrowser-useWebRun
Response TimeStandard LLM latencySub-100ms decisions (hybrid CNN-LLM)
InfrastructureSelf-hosted or CloudFully managed, zero provisioning
Real-time StreamingWebhook-basedNative WebSocket + live video
Human-in-the-loopManual implementationBuilt-in guardrails system
Integration OptionsPython SDKREST, WebSocket, MCP, OpenAI-compatible

The Core Concept Remains the Same

Both platforms share the same mental model: you describe a task in plain English, and an AI agent executes it in a real browser. If you're comfortable with Browser-use, you already understand WebRun.

Migration by Example

Simple Task Execution

The most common pattern: run a single task and get the result.

Browser-use (Python SDK):

from browser_use_sdk import BrowserUse

client = BrowserUse(api_key="bu_...")

task = client.tasks.create_task(
    task="Search for the top 10 Hacker News posts and return the title and url.",
    llm="gpt-4.1"
)

result = task.complete()
print(result.output)

WebRun (REST API):

import requests

response = requests.post(
    "https://connect.webrun.ai/start/run-task",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer enig_..."
    },
    json={
        "taskDetails": "Search for the top 10 Hacker News posts and return the title and url."
    }
)

result = response.json()
print(result["result"]["data"]["message"])

WebRun (JavaScript):

const response = await fetch("https://connect.webrun.ai/start/run-task", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer enig_..."
  },
  body: JSON.stringify({
    taskDetails: "Search for the top 10 Hacker News posts and return the title and url."
  })
});

const result = await response.json();
console.log(result.result.data.message);

Instead of instantiating an SDK client, you make a direct HTTP request. No package installation required—works from any language that can make HTTP calls.

Multi-Step Sessions

For workflows that require multiple sequential tasks in the same browser context.

Browser-use:

from browser_use_sdk import BrowserUse

client = BrowserUse(api_key="bu_...")

task = client.tasks.create_task(
    task="Go to amazon.com",
    session_id="existing_session"
)
await task.complete()

task2 = client.tasks.create_task(
    task="Search for wireless keyboards",
    session_id=task.session_id
)
result = await task2.complete()

WebRun:

import requests

headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer enig_..."
}

# Create session
session = requests.post(
    "https://connect.webrun.ai/start/start-session",
    headers=headers,
    json={
        "taskDetails": "Go to amazon.com",
        "startingUrl": "https://amazon.com"
    }
).json()

session_id = session["sessionId"]

# Send follow-up task
result = requests.post(
    "https://connect.webrun.ai/start/send-message",
    headers=headers,
    json={
        "sessionId": session_id,
        "message": {
            "actionType": "newTask",
            "newState": "start",
            "taskDetails": "Search for wireless keyboards"
        }
    }
).json()

# Terminate when done
requests.post(
    "https://connect.webrun.ai/start/send-message",
    headers=headers,
    json={
        "sessionId": session_id,
        "message": {"actionType": "state", "newState": "terminate"}
    }
)

Real-time Streaming

Browser-use provides streaming via their SDK. WebRun offers native WebSocket streaming with live video.

Browser-use:

from browser_use_sdk import AsyncBrowserUse

client = AsyncBrowserUse(api_key="bu_...")

task = await client.tasks.create_task(
    task="Find top 10 Hacker News articles"
)

async for step in task.stream():
    print(f"Step {step.number}: {step.url} ({step.next_goal})")

result = await task.complete()

WebRun:

import { io } from "socket.io-client";

const session = await fetch("https://connect.webrun.ai/start/start-session", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer enig_..."
  },
  body: JSON.stringify({
    taskDetails: "Find top 10 Hacker News articles"
  })
}).then(r => r.json());

const socket = io("https://connect.webrun.ai", {
  auth: { sessionId: session.sessionId },
  transports: ["websocket"]
});

socket.on("message", (data) => {
  switch (data.type) {
    case "agent":
      console.log("Thinking:", data.content);
      break;
    case "action":
      console.log("Action:", data.data.name);
      break;
    case "task_completed":
      console.log("Done:", data.data.message);
      socket.disconnect();
      break;
  }
});

WebRun also provides live video streaming of the browser session—something you won't get with Browser-use out of the box.

MCP Integration

If you're using MCP with Claude Desktop or Cline, migration is just a config change.

Browser-use:

{
  "mcpServers": {
    "browser-use": {
      "command": "uvx",
      "args": ["browser-use-mcp-server@latest"]
    }
  }
}

WebRun:

{
  "mcpServers": {
    "WebRun": {
      "url": "https://connect.webrun.ai/mcp/sse?apiKey=YOUR_API_KEY"
    }
  }
}

Restart Claude Desktop, and you're running on WebRun.

Handling Long-Running Tasks

WebRun's REST API returns results inline when possible. Most browser tasks complete in 10-40 seconds. WebRun waits up to 50 seconds for your task to finish, meaning you typically get results in a single request.

For longer tasks, you'll receive a pollUrl to check status:

async function runTask(taskDetails, apiKey) {
  const response = await fetch("https://connect.webrun.ai/start/run-task", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`
    },
    body: JSON.stringify({ taskDetails })
  });

  const data = await response.json();

  if (data.status === "complete") {
    return data.result;
  }

  if (data.status === "pending") {
    return await pollForResult(data.sessionId, data.taskId, apiKey);
  }

  throw new Error(data.message || "Task failed");
}

async function pollForResult(sessionId, taskId, apiKey) {
  const maxAttempts = 60;
  const interval = 2000;

  for (let i = 0; i < maxAttempts; i++) {
    const res = await fetch(
      `https://connect.webrun.ai/task/${sessionId}/${taskId}`,
      { headers: { "Authorization": `Bearer ${apiKey}` } }
    );

    const data = await res.json();

    if (data.type === "task_completed") return data;
    if (data.type === "guardrail_trigger") return data;
    if (!data.success && data.type === "failed") throw new Error(data.error);

    await new Promise(r => setTimeout(r, interval));
  }

  throw new Error("Task timeout");
}

New Capabilities You Get for Free

Guardrails

WebRun includes a built-in system for handling situations where the agent needs human input—login credentials, purchase approvals, CAPTCHA help, or clarification on ambiguous instructions.

socket.on("message", (data) => {
  if (data.type === "guardrail_trigger") {
    console.log("Agent needs input:", data.data.value);
    
    socket.emit("message", {
      actionType: "guardrail",
      taskDetails: "The password is: hunter2",
      newState: "resume"
    });
  }
});

Live Video Streaming

Watch your agent work in real-time. Get the stream URL from your session and embed it in your UI or open in browser.

OpenAI-Compatible Endpoint

Already using LangChain, LlamaIndex, or the OpenAI SDK? WebRun provides a drop-in compatible endpoint:

from openai import OpenAI

client = OpenAI(
    api_key="enig_...",
    base_url="https://connect.webrun.ai/v1"
)

response = client.chat.completions.create(
    model="webrun-agent",
    messages=[
        {"role": "user", "content": "Go to google.com and search for Anthropic"}
    ]
)

Quick Reference

Browser-useWebRun
client.tasks.create_task()POST /start/run-task
task.complete()Response returned inline (or poll)
task.stream()WebSocket connection
Session managementPOST /start/start-session + /send-message
Terminate session{"actionType": "state", "newState": "terminate"}

Getting Started

  • Get your API key at app.webrun.ai
  • Replace one task to test the waters
  • Try a task that requires login to see guardrails in action
  • Enable video streaming for debugging
The migration is straightforward because the core abstraction is identical: natural language in, browser automation out. WebRun just gives you more control over what happens in between.

Check out our full documentation at docs.webrun.ai for detailed guides and examples.