LumaBrowser — Now in Beta

The programmable browser for your AI agents.

Give your AI agents, QA scripts, and integrations a real browser — with a REST API, built-in MCP server, and network interception. Bring your own AI: connect a local model, OpenAI, or Anthropic key.

lumabrowser — REST API
# Create a tab and navigate
curl -X POST http://localhost:3000/api/browser/tabs \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

# Click with LLM fallback — never break on selector changes
curl -X POST http://localhost:3000/api/browser/tabs/0/click \
  -d '{"selector": "button.submit", "llmFallback": "Click the submit button"}'

# Get the page content
curl http://localhost:3000/api/browser/tabs/0/source?type=text
Built for every developer workflow
AI Builders

The native execution engine for your AI agents.

Point Claude Desktop, OpenClaw, or any MCP-compatible agent at LumaBrowser's built-in MCP server. Navigate, click, and evaluate the DOM natively — no glue code required.

🔬
QA & Data Extraction

Automate the web without fighting the DOM.

SPAs and randomized CSS classes break scripts daily. Add llmFallback to any selector-based command and LumaBrowser's on-board LLM resolves the right element automatically — keeping your scripts stable.

🔗
Backend & Integration

Turn any website's hidden API into a webhook.

Use the CDP-based Network Watcher to intercept HTTP traffic without root certificates or proxy setups, and forward it directly to your backend.

See it in action

Three lines to navigate, click, and extract — against any website.

# Create a tab and navigate to a page
curl -X POST http://localhost:3000/api/browser/tabs \
  -H "Content-Type: application/json" \
  -d '{"url": "https://news.ycombinator.com"}'

# Click with LLM fallback — if the selector breaks, AI finds the right element
curl -X POST http://localhost:3000/api/browser/tabs/0/click \
  -H "Content-Type: application/json" \
  -d '{"selector": ".titleline > a", "llmFallback": "Click the first story link"}'

# Get the page content as clean text
curl http://localhost:3000/api/browser/tabs/0/source?type=text
import requests

# Create a tab and navigate
requests.post("http://localhost:3000/api/browser/tabs", json={
    "url": "https://news.ycombinator.com"
})

# Click with LLM fallback — resilient to DOM changes
requests.post("http://localhost:3000/api/browser/tabs/0/click", json={
    "selector": ".titleline > a",
    "llmFallback": "Click the first story link"
})

# Fill a form — each field has its own LLM fallback
requests.post("http://localhost:3000/api/browser/tabs/0/fill", json={
    "fields": [
        {"selector": "input[name=q]", "value": "LumaBrowser",
         "llmFallback": "The search input"}
    ]
})
// Create a tab and navigate
await fetch("http://localhost:3000/api/browser/tabs", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ url: "https://news.ycombinator.com" })
});

// Click with LLM fallback — AI resolves the selector if it breaks
await fetch("http://localhost:3000/api/browser/tabs/0/click", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    selector: "button.submit",
    llmFallback: "Click the submit button"
  })
});

// Wait for an element — LLM resolves if selector is stale
await fetch("http://localhost:3000/api/browser/tabs/0/wait", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    selector: ".success-msg",
    llmFallback: "The success confirmation message"
  })
});

What this actually looks like

Real request/response flows showing what LumaBrowser handles for you.

POST/api/browser/tabs
{ "url": "https://acme.com/signup" }
200Tab created
{ "id": 0, "url": "https://acme.com/signup", "title": "Sign Up — Acme" }
POST/api/browser/tabs/0/fill
{
  "fields": [
    { "selector": "#full_name", "value": "Jane Doe",
      "llmFallback": "The full name input field" }
  ],
  "llmFallback": "Fill the signup form"
}
MISSSelector #full_name not found — site renamed it to data-field-xk92
llmFallback is set → triggering AI resolution...
TEMPLATETemplate Builder auto-generates page map
{
  "pageInfo": { "selectorStability": "unstable", "jsRendered": true },
  "elements": [
    { "Name": "Full Name Input", "CssSelector": "input[data-field-xk92]",
      "FallbackSelector": "form .field-group:first-child input",
      "Type": "Input" },
    { "Name": "Email Input", "CssSelector": "input[data-field-ml47]",
      "Type": "Input" },
    { "Name": "Submit Button", "CssSelector": "button.btn-register",
      "Type": "Button" }
  ]
}
LLMAI matches “The full name input field” → input[data-field-xk92]
Prompt: "Action: fill | Description: The full name input field
  Page template elements:
  - "Full Name Input" (Input): input[data-field-xk92]
  - "Email Input" (Input): input[data-field-ml47]
  ..."

→ input[data-field-xk92]
200Form filled — resolved selector returned
{
  "success": true,
  "message": "Form filled successfully (resolved by LLM fallback)",
  "data": {
    "filled": 1,
    "resolvedSelector": "input[data-field-xk92]"
  }
}
GET/api/browser/tabs/0/source
Compare: ?type=full  vs  ?type=clean  vs  ?type=text
?type=full — Raw HTML (3,847 tokens)
<!DOCTYPE html>
<html lang="en" data-theme="dark" data-build="a8f3c">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="...">
  <title>Dashboard — Acme Corp</title>
  <link rel="stylesheet" href="/assets/main.c7x92k.css">
  <link rel="stylesheet" href="/assets/vendor.d83hf.css">
  <script src="/assets/runtime.k29d.js" defer></script>
  <script src="/assets/app.m48fk.js" defer></script>
  <style>.css-1a2b3c{display:flex}
  .css-4d5e6f{margin:0 auto;max-width:1200px}
  .css-7g8h9i{font-family:Inter,sans-serif}
  /* ... 847 more lines of CSS ... */</style>
  <script>window.__NEXT_DATA__={props:{pageProps:
  {session:{user:{id:"usr_382",name:"Jane"},
  token:"eyJhbG..."}}},page:"/dashboard"}
  </script>
</head>
<body>
  <div id="__next">
    <div class="css-1a2b3c">
      <nav class="css-k3m8x2">
        <img src="data:image/svg+xml;base64,PHN2..."
             alt="" class="css-p9q2r1" />
        <a href="/" class="css-m4n5o6">Dashboard</a>
        <a href="/settings" class="css-m4n5o6">Settings</a>
      </nav>
      <main class="css-4d5e6f">
        <h1 class="css-7g8h9i">Welcome back, Jane</h1>
        <div class="css-a1b2c3">
          <div class="css-d4e5f6">Revenue</div>
          <span class="css-g7h8i9">$12,450</span>
        </div>
        <!-- ... 200+ more nodes ... -->
?type=clean — Cleaned HTML (680 tokens)
<nav>
  <a href="/">Dashboard</a>
  <a href="/settings">Settings</a>
</nav>
<main>
  <h1>Welcome back, Jane</h1>
  <div class="metric-card">
    <div>Revenue</div>
    <span>$12,450</span>
  </div>
  <div class="metric-card">
    <div>Active Users</div>
    <span>1,284</span>
  </div>
  <table class="data-table">
    <thead>
      <tr><th>Product</th><th>Sales</th><th>Revenue</th></tr>
    </thead>
    <tbody>
      <tr><td>Widget Pro</td><td>342</td><td>$8,550</td></tr>
      <tr><td>Gadget X</td><td>156</td><td>$3,900</td></tr>
    </tbody>
  </table>
  <a href="/reports">View full report &rarr;</a>
</main>
?type=text — Plain text (89 tokens)
Dashboard | Settings

Welcome back, Jane

Revenue: $12,450
Active Users: 1,284

Product    Sales    Revenue
Widget Pro   342    $8,550
Gadget X     156    $3,900

View full report →
POST/api/ai-chat/run — one prompt, entire workflow
{
  "prompt": "Log into acme.com/login with [email protected] / demo123,
             go to settings, change company name to 'Acme Industries'",
  "autoCloseTab": false,
  "includeScreenshot": true
}
AGENTAutonomous loop: 4 iterations, 7 tool calls
1. navigate → acme.com/login (template attached)
2. fill_form → email + password
3. click → Login button (url changed → /dashboard)
4. wait_for → .dashboard-content 
5. navigate → /settings (template generated)
6. fill_form → company name = "Acme Industries"
7. click → Save Changes 
200Structured result with summary, tab, and screenshot
{
  "success": true,
  "summary": "Logged in and updated company name to Acme Industries",
  "finalResponse": "Done! I logged into acme.com, navigated to...",
  "tabId": 0,
  "iterations": 4,
  "durationMs": 18420,
  "toolCalls": [
    { "tool": "navigate", "durationMs": 1200 },
    { "tool": "fill_form", "durationMs": 340 },
    { "tool": "click", "durationMs": 890 },
    { "tool": "wait_for", "durationMs": 1100 },
    { "tool": "navigate", "durationMs": 1450 },
    { "tool": "fill_form", "durationMs": 280 },
    { "tool": "click", "durationMs": 760 }
  ],
  "screenshot": "data:image/png;base64,iVBOR..."
}

What the AI Chat agent actually does behind the scenes — with Template Builder enabled for faster targeting.

POST/api/ai-chat/run
{ "prompt": "Log into acme.com/login with [email protected] / demo123, go to settings, change company name to 'Acme Industries'." }
Iter
Tool
What happened
#1
navigate
Navigate tab 0 to https://acme.com/login
get_template
Template exists for /login → returns 5 elements incl. input#email, input#password, button.login-btn
#2
fill_form
Fill input#email = "[email protected]", input#password = "demo123" — selectors from template, instant match
click
Click button.login-btn — "Log In" button from template
wait_for
Wait for .dashboard-content to appear → visible in 1.2s
#3
navigate
Navigate to /settings — template auto-generated (no cache), 8 elements extracted
generate_template
No template cached → LLM analyzes page (HTML + screenshot) → generates template with input#company-name, button.save-settings, etc.
#4
fill_form
Clear & fill input#company-name = "Acme Industries" — from freshly generated template
click
Click button.save-settings — "Save Changes"
wait_for
Wait for .toast-success → "Settings saved successfully" appears in 0.8s
complete
Agent returns final response. 4 iterations, 10 tool calls, 0 failures. Template cache means the login page will be instant next time.
Built-in extensions included with every install

AI Chat Sidebar

A built-in LLM assistant that can see and control the browser. Ask it to navigate pages, fill forms, extract data, or run multi-step automations — conversationally. It has full access to every browser tool and streams responses in real time.

  • Agentic tool loop — up to 10 iterations per message
  • Persistent conversation history in SQLite
  • Configurable model: local, OpenAI, or Anthropic
  • Template Builder integration for smarter selectors
Go to Hacker News and tell me the top 3 stories
navigate get_source

Here are the top 3 stories on Hacker News right now:

  1. Show HN: LumaBrowser — programmable browser for AI agents
  2. Why CSS selectors break and how LLMs fix them
  3. Building an MCP server from scratch in Node.js

Network Watcher

Monitor HTTP traffic at the browser level using Chrome DevTools Protocol. Define URL patterns, and LumaBrowser captures matching requests and forwards the full request/response to your webhook — no proxy, no root certs.

  • Wildcard URL pattern matching
  • Filter by HTTP method (GET, POST, etc.)
  • Capture headers and response bodies
  • Trigger statistics and per-watcher history
  • REST API and MCP tool support
Active Watchers
*api.stripe.com/v1/charges*
POST 142 triggers
→ https://my-backend.com/payments
*api.example.com/v2/orders*
* 38 triggers
→ https://hooks.slack.com/services/...
*internal-api.corp.net/*
GET 7 triggers
→ https://logger.internal/webhook

Template Builder

The first time you visit a page, the LLM analyzes the full DOM and generates a cached selector map. Every subsequent visit uses the cached template — slashing token usage by 95%+ and making automation near-instant.

  • LLM analyzes page once, caches the selector map
  • Primary + fallback selectors for resilience
  • Handles SPAs with randomized class names
  • Repeating item extraction (lists, tables)
  • Cached in SQLite — works offline after first run
Token Usage Comparison
First visit (LLM analyzes DOM)
~12,400 tokens
Cached visits (template reuse)
~380 tokens
97% fewer tokens on repeat visits
Cached template output:
{
  "elements": [
    { "name": "Login Button",
      "primary": "button[data-testid='login']",
      "fallbacks": ["button.auth-cta", "#login-btn"] },
    { "name": "Email Field",
      "primary": "input[name='email']",
      "fallbacks": ["input[type='email']"] }
  ]
}

Timed Tasks

Schedule recurring LLM-driven automations. Each execution runs a full agentic loop with browser tools — navigate, click, extract, and report back via webhook. Set it and forget it.

  • Configurable repeat intervals (minutes to days)
  • Webhook callbacks on completion with full results
  • Execution history with step-by-step logs
  • Per-task model selection
Check Product Prices Every 1h Active
Scrape Job Listings Every 6h Active
Submit Daily Report Every 24h Paused

Notification Interceptor

Captures browser Notification API calls from any page and forwards them to your webhook. Monitor alerts, messages, or status changes from any web app — without polling.

  • Intercepts title, body, icon, badge, tag, and data
  • Forward to Slack, Discord, or any webhook URL
  • Works with any site that uses the Notification API
  • Test mode to verify webhook connectivity
Webhook Payload
{
  "source": "app.example.com",
  "title": "New message from Sarah",
  "body": "Hey, the deploy finished!",
  "timestamp": "2026-03-29T14:22:00Z",
  "url": "https://app.example.com/chat"
}

Local WebGPU Inference

Run language models directly on your GPU — no API keys, no cloud, no cost. LumaBrowser ships with WebGPU-accelerated inference using Qwen 2.5 models. Fully private, fully local.

  • Qwen 2.5 series (0.5B to 7B parameters)
  • GPU-accelerated via WebGPU — no CUDA required
  • Zero data leaves your machine
  • Available as a provider for all extensions
WebGPU LLM
ModelQwen 2.5 — 3B
BackendWebGPU (local)
API KeyNot required
Data SentNone
Extensible by Design

Build on top of LumaBrowser.

Every major feature — Network Watcher, Template Builder, AI Chat, Timed Tasks, even local WebGPU inference — is a modular extension. Disable what you don't need, or build your own with the extension API: custom REST routes, MCP tools, and UI panels, all hot-loaded at startup.

Custom REST Routes MCP Tool Registration UI Panels & Sidebars IPC Hooks Per-Extension LLM Slots SQLite Persistence
LumaBrowser Core
Network Watcher
Template Builder
AI Chat
Timed Tasks
WebGPU LLM
Your Extension
Free to Use No API Keys Required
MCP Native Claude Desktop & OpenClaw Ready
REST API Language Agnostic
More by LumaByte
OpenGridJs

A lightweight JavaScript data grid with virtual scrolling, sortable columns, context menus, column reordering, and CSV export. Fast and dependency-free.

ResonantJs

A lightweight reactive UI library for building dynamic interfaces with minimal overhead. Simple API, no build step, no virtual DOM.

Textbookly

The textbook price comparison engine. Find the best deals on textbooks across multiple retailers in one search.

Free Developer APIs

Explore our collection of free, no-auth-required APIs for your projects.