Unbrowser is a free, open source web browsing API that learns from browsing patterns and progressively optimizes to deliver faster, more reliable content extraction. Everything runs locally on your machine.
Run Unbrowser locally with a single command:
# Run as MCP server for Claude Desktop
npx llm-browser
# Or install globally
npm install -g llm-browser
llm-browser
The API will be available at http://localhost:3001.
curl -X POST http://localhost:3001/v1/browse \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com"
}'
import { createUnbrowser } from '@unbrowser/core';
// Runs 100% locally on your machine
const browser = createUnbrowser();
const result = await browser.browse('https://example.com');
console.log(result.content.markdown);
console.log('Loaded in:', result.metadata.loadTime, 'ms');
console.log('Tier used:', result.metadata.tier);
import requests
response = requests.post(
'http://localhost:3001/v1/browse',
headers={
'Content-Type': 'application/json'
},
json={
'url': 'https://example.com'
}
)
data = response.json()
print(data['data']['content']['markdown'])
{
"success": true,
"data": {
"url": "https://example.com",
"finalUrl": "https://example.com/",
"title": "Example Domain",
"content": {
"markdown": "# Example Domain\n\nThis domain is for use in examples...",
"text": "Example Domain\n\nThis domain is for use in examples..."
},
"metadata": {
"loadTime": 145,
"tier": "intelligence",
"tiersAttempted": ["intelligence"]
}
}
}
tier field shows which rendering tier was used.
Lower tiers (intelligence, lightweight) are faster and cheaper.
The system automatically escalates to higher tiers when needed.
Unbrowser uses a tiered approach to minimize latency and cost:
| Tier | Latency | Best For |
|---|---|---|
| Intelligence | ~50-200ms | Static pages, cached patterns, API responses |
| Lightweight | ~200-500ms | Simple JavaScript, SSR frameworks |
| Playwright | ~2-5s | Complex SPAs, heavy JavaScript, authentication |
You can control which tiers are used:
// Limit to fast tiers only (skip Playwright)
const result = await client.browse('https://example.com', {
maxCostTier: 'lightweight',
maxLatencyMs: 1000
});
Browse multiple URLs in parallel:
const results = await client.batch([
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3'
], {
contentType: 'markdown',
maxChars: 5000
});
for (const result of results) {
console.log(result.url, result.success ? 'OK' : 'Failed');
}
When running locally, there are no rate limits. You can make as many requests as your machine can handle.
try {
const result = await browser.browse('https://example.com');
} catch (error) {
if (error.code === 'INVALID_URL') {
console.log('Invalid URL:', error.message);
} else if (error.code === 'FETCH_FAILED') {
console.log('Fetch failed:', error.message);
} else {
console.log('Error:', error.message);
}
}
INVALID_URL - URL is malformed or blockedFETCH_FAILED - Could not fetch the URLTIMEOUT - Request timed out