# Cloud browser (/docs/use-cases/remote-browser)

<!-- agent-signals: reading_time_min: 13 · est_tokens: 8055 · updated: 2026-07-30 -->
Related: [Coding Agents](/docs/use-cases/coding-agents.md), [Computer use](/docs/use-cases/computer-use.md), [GitHub Actions CI/CD](/docs/use-cases/ci-cd.md), [Run Kubernetes with k3s](/docs/use-cases/k3s.md), [Amp](/docs/agents/amp.md)

<Note>
  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).
</Note>

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 [#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+

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```bash  
      npm i e2b @onkernel/sdk playwright-core
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```bash  
      pip install e2b kernel playwright
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

Set your keys in the environment:

```bash title=".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 [#examples]

Here are three common patterns for using cloud browsers with E2B sandboxes.

<CardGroup cols="3">
  <Card title="Screenshot app endpoints" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M12.6974 3.5H11.303C10.5884 3.5 10.2311 3.5 9.91067 3.612C9.71499 3.68039 9.53113 3.77879 9.36568 3.90367C9.09474 4.10816 8.89655 4.40544 8.50018 5L8.50017 5.00001C8.29717 5.30453 7.99794 5.75337 7.87867 5.87871C7.58314 6.18927 7.19563 6.39666 6.77329 6.47029C6.60284 6.5 6.41985 6.5 6.05387 6.5C5.07379 6.5 4.58376 6.5 4.18307 6.61342C3.18074 6.89716 2.39734 7.68055 2.1136 8.68289C2.00018 9.08357 2.00018 9.57361 2.00018 10.5537V14.5C2.00018 17.3284 2.00018 18.7426 2.87886 19.6213C3.75754 20.5 5.17176 20.5 8.00018 20.5H16.0002C18.8286 20.5 20.2428 20.5 21.1215 19.6213C22.0002 18.7426 22.0002 17.3284 22.0002 14.5V10.5537C22.0002 9.57361 22.0002 9.08357 21.8868 8.68289C21.603 7.68055 20.8196 6.89716 19.8173 6.61342C19.4166 6.5 18.9266 6.5 17.9465 6.5C17.5805 6.5 17.3975 6.5 17.2271 6.47029C16.8047 6.39666 16.4172 6.18927 16.1217 5.87871C16.0024 5.75336 15.7032 5.30451 15.5002 5C15.1038 4.40544 14.9056 4.10816 14.6347 3.90367C14.4692 3.77879 14.2854 3.68039 14.0897 3.612C13.7693 3.5 13.412 3.5 12.6974 3.5Z&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M16.0002 13C16.0002 15.2091 14.2093 17 12.0002 17C9.79104 17 8.00018 15.2091 8.00018 13C8.00018 10.7909 9.79104 9 12.0002 9C14.2093 9 16.0002 10.7909 16.0002 13Z&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M19.1252 9.5H19.0002M19.2502 9.5C19.2502 9.63807 19.1383 9.75 19.0002 9.75C18.8621 9.75 18.7502 9.63807 18.7502 9.5C18.7502 9.36193 18.8621 9.25 19.0002 9.25C19.1383 9.25 19.2502 9.36193 19.2502 9.5Z&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="#screenshot-app-endpoints">
    Deploy a web app in a sandbox, screenshot every route
  </Card>

  <Card title="Agent data extraction" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M13 7H11C8.19108 7 6.78661 7 5.77772 7.67412C5.34096 7.96596 4.96596 8.34096 4.67412 8.77772C4 9.78661 4 11.1911 4 14C4 16.8089 4 18.2134 4.67412 19.2223C4.96596 19.659 5.34096 20.034 5.77772 20.3259C6.78661 21 8.19108 21 11 21H13C15.8089 21 17.2134 21 18.2223 20.3259C18.659 20.034 19.034 19.659 19.3259 19.2223C20 18.2134 20 16.8089 20 14C20 11.1911 20 9.78661 19.3259 8.77772C19.034 8.34096 18.659 7.96596 18.2223 7.67412C17.2134 7 15.8089 7 13 7Z&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M4 14H2&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M10 17H14&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M22 14H20&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M15 11V13&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M9 11V13&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M12 7C12 5.11438 12 4.17157 11.4142 3.58579C10.8284 3 9.88562 3 8 3&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="#agent-data-extraction">
    Let an LLM autonomously browse and extract data
  </Card>

  <Card title="Live browser preview" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M2 8C2 8 6.47715 3 12 3C17.5228 3 22 8 22 8&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M21.544 13.045C21.848 13.4713 22 13.6845 22 14C22 14.3155 21.848 14.5287 21.544 14.955C20.1779 16.8706 16.6892 21 12 21C7.31078 21 3.8221 16.8706 2.45604 14.955C2.15201 14.5287 2 14.3155 2 14C2 13.6845 2.15201 13.4713 2.45604 13.045C3.8221 11.1294 7.31078 7 12 7C16.6892 7 20.1779 11.1294 21.544 13.045Z&#x22; stroke=&#x22;currentColor&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M15 14C15 12.3431 13.6569 11 12 11C10.3431 11 9 12.3431 9 14C9 15.6569 10.3431 17 12 17C13.6569 17 15 15.6569 15 14Z&#x22; stroke=&#x22;currentColor&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="#live-browser-preview">
    Watch the browser in real time via Kernel's live view
  </Card>
</CardGroup>

***

## Screenshot app endpoints [#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.

<Steps>
  <Step title="Create the sandbox and start your app">
    <CodeGroup>
      <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
        <CodeBlockTabsList>
          <CodeBlockTabsTrigger value="JavaScript & TypeScript">
            JavaScript & TypeScript
          </CodeBlockTabsTrigger>

          <CodeBlockTabsTrigger value="Python">
            Python
          </CodeBlockTabsTrigger>
        </CodeBlockTabsList>

        <CodeBlockTab value="JavaScript & TypeScript">
          ```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("<h1>Home</h1><p>Welcome to the app.</p>")

          @app.get("/about")
          def about():
              return HTMLResponse("<h1>About</h1><p>About this app.</p>")

          @app.get("/dashboard")
          def dashboard():
              return HTMLResponse("<h1>Dashboard</h1><p>Your dashboard.</p>")
          `

          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' },
          )
          ```
        </CodeBlockTab>

        <CodeBlockTab value="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("<h1>Home</h1><p>Welcome to the app.</p>")

          @app.get("/about")
          def about():
              return HTMLResponse("<h1>About</h1><p>About this app.</p>")

          @app.get("/dashboard")
          def dashboard():
              return HTMLResponse("<h1>Dashboard</h1><p>Your dashboard.</p>")
          """

          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",
          )
          ```
        </CodeBlockTab>
      </CodeBlockTabs>
    </CodeGroup>
  </Step>

  <Step title="Screenshot each route with Kernel">
    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.

    <CodeGroup>
      <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
        <CodeBlockTabsList>
          <CodeBlockTabsTrigger value="JavaScript & TypeScript">
            JavaScript & TypeScript
          </CodeBlockTabsTrigger>

          <CodeBlockTabsTrigger value="Python">
            Python
          </CodeBlockTabsTrigger>
        </CodeBlockTabsList>

        <CodeBlockTab value="JavaScript & TypeScript">
          ```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()
          ```
        </CodeBlockTab>

        <CodeBlockTab value="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()
          ```
        </CodeBlockTab>
      </CodeBlockTabs>
    </CodeGroup>
  </Step>
</Steps>

Full example:

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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("<h1>Home</h1><p>Welcome to the app.</p>")

      @app.get("/about")
      def about():
          return HTMLResponse("<h1>About</h1><p>About this app.</p>")

      @app.get("/dashboard")
      def dashboard():
          return HTMLResponse("<h1>Dashboard</h1><p>Your dashboard.</p>")
      `

      // 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()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="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("<h1>Home</h1><p>Welcome to the app.</p>")

      @app.get("/about")
      def about():
          return HTMLResponse("<h1>About</h1><p>About this app.</p>")

      @app.get("/dashboard")
      def dashboard():
          return HTMLResponse("<h1>Dashboard</h1><p>Your dashboard.</p>")
      """

      # 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()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

***

## Agent data extraction [#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 title=".env"
ANTHROPIC_API_KEY=sk-ant-***
```

<Steps>
  <Step title="Create the sandbox with API keys">
    <CodeGroup>
      <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
        <CodeBlockTabsList>
          <CodeBlockTabsTrigger value="JavaScript & TypeScript">
            JavaScript & TypeScript
          </CodeBlockTabsTrigger>

          <CodeBlockTabsTrigger value="Python">
            Python
          </CodeBlockTabsTrigger>
        </CodeBlockTabsList>

        <CodeBlockTab value="JavaScript & TypeScript">
          ```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,
          })
          ```
        </CodeBlockTab>

        <CodeBlockTab value="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,
          )
          ```
        </CodeBlockTab>
      </CodeBlockTabs>
    </CodeGroup>
  </Step>

  <Step title="Write and run the agent">
    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.

    <CodeGroup>
      <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
        <CodeBlockTabsList>
          <CodeBlockTabsTrigger value="JavaScript & TypeScript">
            JavaScript & TypeScript
          </CodeBlockTabsTrigger>

          <CodeBlockTabsTrigger value="Python">
            Python
          </CodeBlockTabsTrigger>
        </CodeBlockTabsList>

        <CodeBlockTab value="JavaScript & TypeScript">
          ```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()
          ```
        </CodeBlockTab>

        <CodeBlockTab value="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()
          ```
        </CodeBlockTab>
      </CodeBlockTabs>
    </CodeGroup>
  </Step>
</Steps>

Full example:

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="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()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

***

## Live browser preview [#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.

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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
      // <iframe src={liveViewUrl}></iframe>

      // Read-only mode (no mouse/keyboard interaction)
      // liveViewUrl + '?readOnly=true'
      ```
    </CodeBlockTab>

    <CodeBlockTab value="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
      # <iframe src={live_view_url}></iframe>

      # Read-only mode (no mouse/keyboard interaction)
      # live_view_url + '?readOnly=true'
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

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 [#related-guides]

<CardGroup cols="3">
  <Card title="Computer use" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M14 21H16M14 21C13.1716 21 12.5 20.3284 12.5 19.5V17L12 17M14 21H10M10 21H8M10 21C10.8284 21 11.5 20.3284 11.5 19.5V17L12 17M12 17V21&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M16 3H8C5.17157 3 3.75736 3 2.87868 3.87868C2 4.75736 2 6.17157 2 9V11C2 13.8284 2 15.2426 2.87868 16.1213C3.75736 17 5.17157 17 8 17H16C18.8284 17 20.2426 17 21.1213 16.1213C22 15.2426 22 13.8284 22 11V9C22 6.17157 22 4.75736 21.1213 3.87868C20.2426 3 18.8284 3 16 3Z&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/docs/use-cases/computer-use">
    Local browser automation with virtual desktops
  </Card>

  <Card title="Sandbox lifecycle" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M4 2V5.13219C4 5.42605 4.36724 5.55908 4.55527 5.33333C6.3854 3.2875 9.04499 2 12.0051 2C17.5251 2 22 6.47715 22 12C22 15.9582 19.7015 19.3793 16.367 21&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M11.7347 22.0001C12.2016 22.0001 12.6611 21.9688 13.1111 21.9084M2.26537 8.66675C2.15297 9.06394 2.06477 9.46536 2 9.86901M2.03457 13.5381C2.10487 13.9381 2.19644 14.3343 2.30852 14.7245M3.83292 17.9963C4.07124 18.3497 4.3296 18.69 4.6071 19.0147M7.42857 21.3607C7.78228 21.5632 8.15042 21.7464 8.53228 21.9084&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/docs/sandbox">
    Create, manage, and control sandbox lifecycle
  </Card>

  <Card title="Running commands" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M4.00004 17C4.00004 17 9.99999 12.5811 10 11C10 9.41884 4 5 4 5&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M12 19H20&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/docs/commands">
    Run terminal commands inside the sandbox
  </Card>
</CardGroup>
