diff --git a/docs.json b/docs.json index 41ff2fea..a4ee2fe0 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..23282b36 --- /dev/null +++ b/docs/use-cases/remote-browser.mdx @@ -0,0 +1,667 @@ +--- +title: "Remote browser" +description: "Use Kernel cloud browsers with E2B sandboxes for web scraping, screenshots, and autonomous browsing agents." +icon: "globe" +--- + + +This guide covers **remote browsers** powered by [Kernel](https://www.kernel.computer/) — 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). + + +Remote browsers run on Kernel's infrastructure, not inside your sandbox. Your agent connects to them over the network via Playwright or Puppeteer. This keeps sandboxes lightweight and lets you spin up many browsers in parallel. + +Kernel handles stealth mode, CAPTCHA solving, residential proxies, and persistent browser profiles out of the box. + +## Prerequisites + +- An [E2B API key](https://e2b.dev/dashboard?tab=keys) +- A [Kernel API key](https://www.kernel.computer/) +- 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 remote 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 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 + +