diff --git a/docs.json b/docs.json index a45830f5..7d21cd30 100644 --- a/docs.json +++ b/docs.json @@ -47,7 +47,8 @@ "pages": [ "docs/use-cases/coding-agents", "docs/use-cases/computer-use", - "docs/use-cases/ci-cd" + "docs/use-cases/ci-cd", + "docs/use-cases/remote-browser" ] }, { diff --git a/docs/use-cases/remote-browser.mdx b/docs/use-cases/remote-browser.mdx new file mode 100644 index 00000000..2d3eba83 --- /dev/null +++ b/docs/use-cases/remote-browser.mdx @@ -0,0 +1,667 @@ +--- +title: "Cloud browser" +description: "Use Kernel cloud browsers with E2B sandboxes to give your agents access to the internet." +icon: "globe" +--- + + +This guide covers **cloud browsers** powered by [Kernel](https://www.kernel.sh/) — cloud Chromium instances your code controls via [CDP](https://chromedevtools.github.io/devtools-protocol/) or the [Kernel SDK](https://www.kernel.sh/docs/sdk/overview). For **local browser automation** using a virtual desktop, see [Computer use](/docs/use-cases/computer-use). + + +Cloud browsers run on Kernel's managed infrastructure, not inside your sandbox. This gives you sub-second browser startup, [persistent sessions you can pause and resume](https://www.onkernel.com/docs/browsers/persistence) across hours or days, and reusable browser state. Your agent connects to them over the network via CDP, BiDi, or their CUA API. + +Kernel handles CAPTCHA solving, residential proxies, authentication, and observability out of the box. + +## Prerequisites + +- An [E2B API key](https://e2b.dev/dashboard?tab=keys) +- A [Kernel API key](https://dashboard.onkernel.com/api-keys) +- Python 3.10+ / Node.js 18+ + + +```bash JavaScript & TypeScript +npm i e2b @onkernel/sdk playwright-core +``` +```bash Python +pip install e2b kernel playwright +``` + + +Set your keys in the environment: + +```bash .env +E2B_API_KEY=e2b_*** +KERNEL_API_KEY=kernel_*** +``` + +E2B provides a pre-built sandbox template with the Kernel SDK and Playwright already installed: + +| Template | What's included | Best for | +|---|---|---| +| `kernel-browser` | Kernel SDK, Playwright, Browser Use | Screenshots, scraping, app previews, autonomous agents | + +## Examples + +Here are three common patterns for using cloud browsers with E2B sandboxes. + + + + Deploy a web app in a sandbox, screenshot every route + + + Let an LLM autonomously browse and extract data + + + Watch the browser in real time via Kernel's live view + + + +--- + +## Screenshot app endpoints + +Deploy a web app inside an E2B sandbox, get a public URL, then use a Kernel cloud browser to screenshot every route. + + + + + +```typescript JavaScript & TypeScript +import { Sandbox } from 'e2b' + +// A minimal FastAPI app with three routes to screenshot +const FASTAPI_APP = ` +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + +@app.get("/") +def home(): + return HTMLResponse("

Home

Welcome to the app.

") + +@app.get("/about") +def about(): + return HTMLResponse("

About

About this app.

") + +@app.get("/dashboard") +def dashboard(): + return HTMLResponse("

Dashboard

Your dashboard.

") +` + +const sandbox = await Sandbox.create('kernel-browser', { + envs: { KERNEL_API_KEY: process.env.KERNEL_API_KEY! }, + timeoutMs: 300_000, +}) + +await sandbox.files.write('/home/user/app.py', FASTAPI_APP) +await sandbox.commands.run( + 'pip install fastapi uvicorn', + { timeoutMs: 60_000 }, +) +await sandbox.commands.run( + 'uvicorn app:app --host 0.0.0.0 --port 8000', + { background: true, cwd: '/home/user' }, +) +``` +```python Python +import os +from e2b import Sandbox + +# A minimal FastAPI app with three routes to screenshot +FASTAPI_APP = """ +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + +@app.get("/") +def home(): + return HTMLResponse("

Home

Welcome to the app.

") + +@app.get("/about") +def about(): + return HTMLResponse("

About

About this app.

") + +@app.get("/dashboard") +def dashboard(): + return HTMLResponse("

Dashboard

Your dashboard.

") +""" + +sandbox = Sandbox.create( + "kernel-browser", + envs={"KERNEL_API_KEY": os.environ["KERNEL_API_KEY"]}, + timeout=300, +) + +sandbox.files.write("/home/user/app.py", FASTAPI_APP) +sandbox.commands.run( + "pip install fastapi uvicorn", + timeout=60, +) +sandbox.commands.run( + "uvicorn app:app --host 0.0.0.0 --port 8000", + background=True, + cwd="/home/user", +) +``` +
+
+ + +E2B exposes any sandbox port as a public HTTPS endpoint. Write a browsing script into the sandbox that creates a Kernel browser and screenshots each route. + + +```typescript JavaScript & TypeScript +const host = sandbox.getHost(8000) +const appUrl = `https://${host}` + +const BROWSE_SCRIPT = ` +import sys +from kernel import Kernel +from playwright.sync_api import sync_playwright + +app_url = "${appUrl}" +routes = ["/", "/about", "/dashboard"] + +kernel = Kernel() +kb = kernel.browsers.create() + +with sync_playwright() as pw: + browser = pw.chromium.connect_over_cdp(kb.cdp_ws_url) + page = browser.new_page() + page.set_viewport_size({"width": 1280, "height": 720}) + + for route in routes: + page.goto(f"{app_url}{route}", wait_until="networkidle") + name = "home" if route == "/" else route.strip("/") + page.screenshot(path=f"/home/user/{name}.png") + print(f"Captured {route}") + + browser.close() +` + +await sandbox.files.write('/home/user/browse.py', BROWSE_SCRIPT) +const result = await sandbox.commands.run( + 'python3 /home/user/browse.py', + { timeoutMs: 60_000 }, +) +console.log(result.stdout) +await sandbox.kill() +``` +```python Python +host = sandbox.get_host(8000) +app_url = f"https://{host}" + +BROWSE_SCRIPT = f''' +from kernel import Kernel +from playwright.sync_api import sync_playwright + +app_url = "{app_url}" +routes = ["/", "/about", "/dashboard"] + +kernel = Kernel() +kb = kernel.browsers.create() + +with sync_playwright() as pw: + browser = pw.chromium.connect_over_cdp(kb.cdp_ws_url) + page = browser.new_page() + page.set_viewport_size({{"width": 1280, "height": 720}}) + + for route in routes: + page.goto(f"{{app_url}}{{route}}", wait_until="networkidle") + name = "home" if route == "/" else route.strip("/") + page.screenshot(path=f"/home/user/{{name}}.png") + print(f"Captured {{route}}") + + browser.close() +''' + +sandbox.files.write("/home/user/browse.py", BROWSE_SCRIPT) +result = sandbox.commands.run("python3 /home/user/browse.py", timeout=60) +print(result.stdout) +sandbox.kill() +``` + + +
+ +Full example: + + +```typescript JavaScript & TypeScript expandable +import { Sandbox } from 'e2b' + +// A minimal FastAPI app with three routes to screenshot +const FASTAPI_APP = ` +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + +@app.get("/") +def home(): + return HTMLResponse("

Home

Welcome to the app.

") + +@app.get("/about") +def about(): + return HTMLResponse("

About

About this app.

") + +@app.get("/dashboard") +def dashboard(): + return HTMLResponse("

Dashboard

Your dashboard.

") +` + +// 1. Create the sandbox and start the app +const sandbox = await Sandbox.create('kernel-browser', { + envs: { KERNEL_API_KEY: process.env.KERNEL_API_KEY! }, + timeoutMs: 300_000, +}) + +await sandbox.files.write('/home/user/app.py', FASTAPI_APP) +await sandbox.commands.run( + 'pip install fastapi uvicorn', + { timeoutMs: 60_000 }, +) +await sandbox.commands.run( + 'uvicorn app:app --host 0.0.0.0 --port 8000', + { background: true, cwd: '/home/user' }, +) + +// 2. Screenshot each route with a Kernel browser +const host = sandbox.getHost(8000) +const appUrl = `https://${host}` + +const BROWSE_SCRIPT = ` +import sys +from kernel import Kernel +from playwright.sync_api import sync_playwright + +app_url = "${appUrl}" +routes = ["/", "/about", "/dashboard"] + +kernel = Kernel() +kb = kernel.browsers.create() + +with sync_playwright() as pw: + browser = pw.chromium.connect_over_cdp(kb.cdp_ws_url) + page = browser.new_page() + page.set_viewport_size({"width": 1280, "height": 720}) + + for route in routes: + page.goto(f"{app_url}{route}", wait_until="networkidle") + name = "home" if route == "/" else route.strip("/") + page.screenshot(path=f"/home/user/{name}.png") + print(f"Captured {route}") + + browser.close() +` + +await sandbox.files.write('/home/user/browse.py', BROWSE_SCRIPT) +const result = await sandbox.commands.run( + 'python3 /home/user/browse.py', + { timeoutMs: 60_000 }, +) +console.log(result.stdout) +await sandbox.kill() +``` +```python Python expandable +import os +from e2b import Sandbox + +# A minimal FastAPI app with three routes to screenshot +FASTAPI_APP = """ +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + +@app.get("/") +def home(): + return HTMLResponse("

Home

Welcome to the app.

") + +@app.get("/about") +def about(): + return HTMLResponse("

About

About this app.

") + +@app.get("/dashboard") +def dashboard(): + return HTMLResponse("

Dashboard

Your dashboard.

") +""" + +# 1. Create the sandbox and start the app +sandbox = Sandbox.create( + "kernel-browser", + envs={"KERNEL_API_KEY": os.environ["KERNEL_API_KEY"]}, + timeout=300, +) + +sandbox.files.write("/home/user/app.py", FASTAPI_APP) +sandbox.commands.run( + "pip install fastapi uvicorn", + timeout=60, +) +sandbox.commands.run( + "uvicorn app:app --host 0.0.0.0 --port 8000", + background=True, + cwd="/home/user", +) + +# 2. Screenshot each route with a Kernel browser +host = sandbox.get_host(8000) +app_url = f"https://{host}" + +BROWSE_SCRIPT = f''' +from kernel import Kernel +from playwright.sync_api import sync_playwright + +app_url = "{app_url}" +routes = ["/", "/about", "/dashboard"] + +kernel = Kernel() +kb = kernel.browsers.create() + +with sync_playwright() as pw: + browser = pw.chromium.connect_over_cdp(kb.cdp_ws_url) + page = browser.new_page() + page.set_viewport_size({{"width": 1280, "height": 720}}) + + for route in routes: + page.goto(f"{{app_url}}{{route}}", wait_until="networkidle") + name = "home" if route == "/" else route.strip("/") + page.screenshot(path=f"/home/user/{{name}}.png") + print(f"Captured {{route}}") + + browser.close() +''' + +sandbox.files.write("/home/user/browse.py", BROWSE_SCRIPT) +result = sandbox.commands.run("python3 /home/user/browse.py", timeout=60) +print(result.stdout) +sandbox.kill() +``` +
+ +--- + +## Agent data extraction + +Use [Browser Use](https://docs.browser-use.com/) to let an LLM autonomously browse a website and extract data. The agent sees the page via screenshots and decides what to click, type, and navigate. + +This requires an additional LLM API key: + +```bash .env +ANTHROPIC_API_KEY=sk-ant-*** +``` + + + + + +```typescript JavaScript & TypeScript +import { Sandbox } from 'e2b' + +const sandbox = await Sandbox.create('kernel-browser', { + envs: { + KERNEL_API_KEY: process.env.KERNEL_API_KEY!, + ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!, + }, + timeoutMs: 300_000, +}) +``` +```python Python +import os +from e2b import Sandbox + +sandbox = Sandbox.create( + "kernel-browser", + envs={ + "KERNEL_API_KEY": os.environ["KERNEL_API_KEY"], + "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], + }, + timeout=300, +) +``` + + + + +The agent script runs inside the sandbox. Browser Use and its dependencies come pre-installed in the `kernel-browser` template. The script creates a Kernel browser, connects Browser Use, and completes the task autonomously. + + +```typescript JavaScript & TypeScript +const AGENT_SCRIPT = ` +import asyncio +from kernel import Kernel +from browser_use import Agent, Browser, ChatAnthropic + +async def main(): + kernel = Kernel() + kb = kernel.browsers.create() + browser = Browser(cdp_url=kb.cdp_ws_url) + + agent = Agent( + task="Go to https://news.ycombinator.com, find the top 5 stories, and return their titles and point counts as JSON", + llm=ChatAnthropic(model="claude-sonnet-4"), + browser=browser, + ) + result = await agent.run() + print(result) + +asyncio.run(main()) +` + +await sandbox.files.write('/home/user/agent_task.py', AGENT_SCRIPT) +const result = await sandbox.commands.run( + 'python3 /home/user/agent_task.py', + { timeoutMs: 180_000 }, +) +console.log(result.stdout) +await sandbox.kill() +``` +```python Python +AGENT_SCRIPT = ''' +import asyncio +from kernel import Kernel +from browser_use import Agent, Browser, ChatAnthropic + +async def main(): + kernel = Kernel() + kb = kernel.browsers.create() + browser = Browser(cdp_url=kb.cdp_ws_url) + + agent = Agent( + task="Go to https://news.ycombinator.com, find the top 5 stories, and return their titles and point counts as JSON", + llm=ChatAnthropic(model="claude-sonnet-4"), + browser=browser, + ) + result = await agent.run() + print(result) + +asyncio.run(main()) +''' + +sandbox.files.write("/home/user/agent_task.py", AGENT_SCRIPT) +result = sandbox.commands.run("python3 /home/user/agent_task.py", timeout=180) +print(result.stdout) +sandbox.kill() +``` + + + + +Full example: + + +```typescript JavaScript & TypeScript expandable +import { Sandbox } from 'e2b' + +// 1. Create the sandbox with API keys +const sandbox = await Sandbox.create('kernel-browser', { + envs: { + KERNEL_API_KEY: process.env.KERNEL_API_KEY!, + ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!, + }, + timeoutMs: 300_000, +}) + +// 2. Write and run the Browser Use agent +const AGENT_SCRIPT = ` +import asyncio +from kernel import Kernel +from browser_use import Agent, Browser, ChatAnthropic + +async def main(): + kernel = Kernel() + kb = kernel.browsers.create() + browser = Browser(cdp_url=kb.cdp_ws_url) + + agent = Agent( + task="Go to https://news.ycombinator.com, find the top 5 stories, and return their titles and point counts as JSON", + llm=ChatAnthropic(model="claude-sonnet-4"), + browser=browser, + ) + result = await agent.run() + print(result) + +asyncio.run(main()) +` + +await sandbox.files.write('/home/user/agent_task.py', AGENT_SCRIPT) +const result = await sandbox.commands.run( + 'python3 /home/user/agent_task.py', + { timeoutMs: 180_000 }, +) +console.log(result.stdout) +await sandbox.kill() +``` +```python Python expandable +import os +from e2b import Sandbox + +# 1. Create the sandbox with API keys +sandbox = Sandbox.create( + "kernel-browser", + envs={ + "KERNEL_API_KEY": os.environ["KERNEL_API_KEY"], + "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], + }, + timeout=300, +) + +# 2. Write and run the Browser Use agent +AGENT_SCRIPT = ''' +import asyncio +from kernel import Kernel +from browser_use import Agent, Browser, ChatAnthropic + +async def main(): + kernel = Kernel() + kb = kernel.browsers.create() + browser = Browser(cdp_url=kb.cdp_ws_url) + + agent = Agent( + task="Go to https://news.ycombinator.com, find the top 5 stories, and return their titles and point counts as JSON", + llm=ChatAnthropic(model="claude-sonnet-4"), + browser=browser, + ) + result = await agent.run() + print(result) + +asyncio.run(main()) +''' + +sandbox.files.write("/home/user/agent_task.py", AGENT_SCRIPT) +result = sandbox.commands.run("python3 /home/user/agent_task.py", timeout=180) +print(result.stdout) +sandbox.kill() +``` + + +--- + +## Live browser preview + +Kernel provides a live view URL for every browser session — you can watch the browser in real time or embed it in your app. This is useful for debugging, demos, or letting users see what the agent is doing. + + +```typescript JavaScript & TypeScript +import { Sandbox } from 'e2b' + +const sandbox = await Sandbox.create('kernel-browser', { + envs: { KERNEL_API_KEY: process.env.KERNEL_API_KEY! }, + timeoutMs: 300_000, +}) + +const LIVE_VIEW_SCRIPT = ` +from kernel import Kernel + +kernel = Kernel() +browser = kernel.browsers.create() + +# Print the live view URL — accessible from any browser +print(browser.browser_live_view_url) +` + +await sandbox.files.write('/home/user/live_view.py', LIVE_VIEW_SCRIPT) +const result = await sandbox.commands.run( + 'python3 /home/user/live_view.py', + { timeoutMs: 30_000 }, +) +const liveViewUrl = result.stdout.trim() +console.log('Watch the browser:', liveViewUrl) + +// Embed in your app as an iframe +// + +// Read-only mode (no mouse/keyboard interaction) +// liveViewUrl + '?readOnly=true' +``` +```python Python +import os +from e2b import Sandbox + +sandbox = Sandbox.create( + "kernel-browser", + envs={"KERNEL_API_KEY": os.environ["KERNEL_API_KEY"]}, + timeout=300, +) + +LIVE_VIEW_SCRIPT = ''' +from kernel import Kernel + +kernel = Kernel() +browser = kernel.browsers.create() + +# Print the live view URL — accessible from any browser +print(browser.browser_live_view_url) +''' + +sandbox.files.write("/home/user/live_view.py", LIVE_VIEW_SCRIPT) +result = sandbox.commands.run("python3 /home/user/live_view.py", timeout=30) +live_view_url = result.stdout.strip() +print("Watch the browser:", live_view_url) + +# Embed in your app as an iframe +# + +# Read-only mode (no mouse/keyboard interaction) +# live_view_url + '?readOnly=true' +``` + + +The live view URL stays active until the browser is deleted or times out. For more details, see the [Kernel live view documentation](https://www.kernel.sh/docs/browsers/live-view). + +## Related guides + + + + Local browser automation with virtual desktops + + + Create, manage, and control sandbox lifecycle + + + Run terminal commands inside the sandbox + +