> ## Documentation Index
> Fetch the complete documentation index at: https://e2e.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# E2B

> Run Android targets and web targets in E2B sandboxes with the e2b() and e2bBrowsers() providers from @e2e-dev/e2b.

`@e2e-dev/e2b` runs your targets in [E2B](https://e2b.dev) sandboxes:
Android 16 with `e2b()`, a [device provider](https://e2e.com/docs/mobile#hosted-devices), and
Chromium with `e2bBrowsers()` from `@e2e-dev/e2b/web`, a
[browser provider](https://e2e.com/docs/browser#hosted-browsers). Your tests stay the same.

## Authenticate

Set `E2B_API_KEY` in the environment that starts e2e. In CI, store it as
a secret. Copy the key from the [E2B dashboard](https://e2b.dev/dashboard).
For a dedicated E2B cluster, also set `E2B_DOMAIN`. Without a key, the
provider fails with `INVALID_CONFIG`.

## Run Android targets

Each worker gets its own Android sandbox, ready with your `.apk` in about
15 to 45 seconds. The provider installs the `.apk` through agent-device,
like `device.installApp()`, and deletes the sandbox when the run ends.

<Tip>
No Android SDK, emulator, or `adb` on the machine that runs e2e.
</Tip>

Install the integration alongside the mobile engine:

<CodeGroup>
```bash npm
npm install --save-dev e2e @e2e-dev/mobile @e2e-dev/e2b e2b
```

```bash pnpm
pnpm add -D e2e @e2e-dev/mobile @e2e-dev/e2b e2b
```

```bash bun
bun add -d e2e @e2e-dev/mobile @e2e-dev/e2b e2b
```
</CodeGroup>

Set the target's `device` to `e2b()`:

```ts title="e2e.config.ts"

export default {
  targets: [
    {
      name: 'android',
      engine: mobile({ platform: 'android', device: e2b() }),
      app: { bundleId: 'com.example.app', appPath: 'build/app-debug.apk' },
    },
  ],
  workers: 4,
} satisfies E2EConfig;
```

`bundleId` is optional: without it, `app.open()` opens the package that
agent-device reports for the `.apk`.

## Run web targets in browsers

Each worker gets its own Chromium sandbox, and every attempt gets a new
browser context in it, as in a local run. With `scope: 'attempt'`, every
attempt gets a new sandbox instead
([limits of that scope](https://e2e.com/docs/browser#pick-a-lease-scope)).

Install the integration alongside the web engine:

<CodeGroup>
```bash npm
npm install --save-dev e2e @e2e-dev/web @e2e-dev/e2b e2b
```

```bash pnpm
pnpm add -D e2e @e2e-dev/web @e2e-dev/e2b e2b
```

```bash bun
bun add -d e2e @e2e-dev/web @e2e-dev/e2b e2b
```
</CodeGroup>

Build the browser template once, from the Playwright image. Use the image
tag of the Playwright version your `@e2e-dev/web` uses, and give the
template 4 GB of memory, as below:

```ts title="build-template.ts"

const template = Template().fromImage('mcr.microsoft.com/playwright:v1.65.0-noble');
await Template.build(template, 'e2e-chromium', {
  cpuCount: 4,
  memoryMB: 4096,
  onBuildLogs: defaultBuildLogger(),
});
```

Then set the target's `browser` to `e2bBrowsers()`. If you named the
template something else, pass the name as `template`:

```ts title="e2e.config.ts"

export default {
  targets: [
    {
      name: 'e2b-web',
      engine: web({ browser: e2bBrowsers() }),
      app: { url: 'https://staging.example.com' },
    },
  ],
  workers: 4,
} satisfies E2EConfig;
```

The browser runs in E2B's cloud, so `app.url` must be reachable from the
internet, not only from `localhost`.

## Android options

| Option      | Default        | Meaning |
| ----------- | -------------- | ------- |
| `template`  | `'android-16'` | Sandbox template that boots Android. |
| `timeoutMs` | `3600000` (1 hour) | Sandbox lifetime. E2B kills the sandbox after it, even when the run is still using it. |

## Browser options

| Option      | Default          | Meaning |
| ----------- | ---------------- | ------- |
| `template`  | `'e2e-chromium'` | Sandbox template with Playwright's Chromium. |
| `scope`     | `'worker'`       | `'worker'`: one sandbox per worker slot for the run. `'attempt'`: a new sandbox for every attempt. |
| `timeoutMs` | `3600000` (1 hour) | Sandbox lifetime. E2B kills the sandbox after it, even when the run is still using it. |

An unknown option or an invalid value fails with `INVALID_CONFIG` when
the config loads.

## How the sandboxes stay private

Sandboxes refuse public traffic: the provider reaches each one through a
tunnel on `127.0.0.1` that adds E2B's access token, and, as with a local
Chromium, any program on your machine can use that tunnel while the run
holds the lease.

## Limits

- **Android only.** E2B has no iOS sandboxes, so `e2b()` refuses an iOS
  target.
- **Android image.** Android 16 on E2B is x86_64 only, without Google Play
  Services, and renders in software. Apps with native libraries need x86_64
  builds; see [E2B's Android page](https://e2b.dev/docs/use-cases/android).
  The provider installs an `.apk`, not an `.aab`.
- **Billing.** A sandbox is billed while it runs. Android sandboxes and
  worker-scope browser sandboxes run from the start of the run to its end,
  even while no test uses them; an attempt-scope browser sandbox runs only
  for its attempt.
- **Stopped runs.** If the runner is killed before it deletes a sandbox,
  E2B deletes it when `timeoutMs` ends.

## Next

<CardGroup cols={2}>
  <Card title="Hosted devices" icon="mobile" href="/mobile#hosted-devices">
    How a device provider leases devices.
  </Card>
  <Card title="Hosted browsers" icon="globe" href="/browser#hosted-browsers">
    How a browser provider leases browsers.
  </Card>
</CardGroup>
