----
url: https://www.kernel.sh/docs/auth/profiles
----

Profiles let you capture browser state created during a session (cookies and local storage) and reuse it in later sessions. This is the primitive to instantiate [authenticated browsers](https://www.kernel.sh/docs/auth/overview).

## [​](#1-create-a-profile)1. Create a profile

Managed Auth automatically creates browser profiles for each [connection](https://www.kernel.sh/docs/auth/overview) you successfully authenticate. You can also use profiles without Managed Auth. The first step in using profiles is to create one, optionally giving it a meaningful `name` that is unique within your organization.

```
import Kernel, { ConflictError } from '@onkernel/sdk';

const kernel = new Kernel();

try {
  await kernel.profiles.create({ name: 'profiles-demo' });
} catch (err) {
  if (err instanceof ConflictError) {
    // Profile already exists
  } else {
    throw err;
  }
}
```

## [​](#2-start-a-browser-session-using-the-profile-and-save-changes)2. Start a browser session using the profile and save changes

After creating the profile, reference it by its `name` or `id` when creating a browser. Set `save_changes` to true to persist any state created during this session back into the profile when the browser is closed.

```
const kernelBrowser = await kernel.browsers.create({
  profile: {
    name: 'profiles-demo',
    save_changes: true,
  },
});
```

## [​](#3-use-the-browser-then-close-it-to-persist-the-state)3. Use the browser, then close it to persist the state

After using a browser with `save_changes: true`, closing the browser will save cookies and local storage into the profile.

Calling `browser.close()` does **not** save the profile state. You **must** explicitly delete the Kernel browser (or let the browser [timeout](https://www.kernel.sh/docs/browsers/termination#automatic-deletion-via-timeout)) to persist the Profile.

```
console.log('Live view:', kernelBrowser.browser_live_view_url);

// Navigate and create login state...

await kernel.browsers.deleteByID(kernelBrowser.session_id);
```

## [​](#4-start-a-new-session-with-the-saved-profile-read-only)4. Start a new session with the saved profile (read-only)

Create another browser using the same profile name. Omitting `save_changes` leaves the stored profile untouched.

```
const kernelBrowser2 = await kernel.browsers.create({
  profile: { name: 'profiles-demo' },
});

console.log('Live view:', kernelBrowser2.browser_live_view_url);
```

## [​](#loading-a-profile-into-an-existing-browser)Loading a profile into an existing browser

You can load a profile into a browser after it has been created using the [update browser endpoint](https://www.kernel.sh/docs/api-reference/browsers/update-browser-session).

```
// Create a browser without a profile
const kernelBrowser = await kernel.browsers.create();

// Later, load a profile into the browser
await kernel.browsers.update(kernelBrowser.session_id, {
  profile: { name: 'profiles-demo' }
});
```

You cannot load a profile into a browser that was already created with a profile. The browser must have been created without any profile configuration.

## [​](#other-ways-to-use-profiles)Other ways to use profiles

The API and SDKs support listing, deleting, and downloading profile data as JSON. See the [API reference](https://www.kernel.sh/docs/api-reference/profiles/list-profiles) for more details.

## [​](#notes)Notes

* A profile’s `name` must be unique within your organization.
* Profiles store cookies and local storage. Start the session with `save_changes: true` to write changes back when the browser is closed.
* To keep a profile immutable for a run, omit `save_changes` (default) when creating the browser.
* Multiple browsers in parallel can use the same profile, but only one browser should write (`save_changes: true`) to it at a time. Parallel browsers with `save_changes: true` may cause profile corruption and unpredictable behavior.
* Profile data is encrypted end to end using a per-organization key.

----
url: https://www.kernel.sh/docs/reference/mcp-server
----

Our Model Context Protocol (MCP) server lets any compatible AI model or agent launch Chromium browsers, execute Playwright code, capture video replays, and automate web interactions from Kernel’s cloud platform via a single secure endpoint.

## Setup Instructions

### General (Transports)

Use the streamable HTTP endpoint where supported for increased reliability. If your client does not support remote MCP, use `mcp-remote` over stdio. Kernel’s server is a centrally hosted, authenticated remote MCP using OAuth 2.1 with dynamic client registration.

## Authentication

### OAuth (Recommended)

The MCP server uses OAuth 2.1 for user authentication. When you connect through supported clients, you’ll be prompted to authorize access via your browser.

### API Key Authentication

For programmatic access or service-to-service authentication, you can use your Kernel API key instead of OAuth. Add your API key to the MCP configuration:

The server automatically detects non-JWT tokens and treats them as API keys. API key authentication is useful for:

## Connect in your client

### Claude

#### Pro, Max, Team & Enterprise (Claude.ai and Claude Desktop)

1. Go to **Settings → Connectors → Add custom connector**.
2. Enter: **Integration name:** `Kernel`, **Integration URL:** `https://mcp.onkernel.com/mcp`, then click **Add**.
3. In **Settings → Connectors**, click **Connect** next to `Kernel` to launch OAuth and approve.
4. In chat, click **Search and tools** and enable the Kernel tools if needed.

#### Claude Code CLI

**Using Kernel CLI (recommended):**

**Manual setup:**

### Cursor

**Using Kernel CLI (recommended):**

**One-click install:** Click [here](https://cursor.com/en/install-mcp?name=Kernel\&config=eyJ1cmwiOiAiaHR0cHM6Ly9tY3Aub25rZXJuZWwuY29tL21jcCJ9) to install Kernel on Cursor.

#### Manual setup

1. Press **⌘/Ctrl Shift J**.
2. Go to **MCP & Integrations → New MCP server**.
3. Add this configuration:

4) Save. The server will appear in Tools.

### OpenCode

Add the following to your `~/.config/opencode/opencode.jsonc`:

Then authenticate using the OpenCode CLI:

### Goose

**Using Kernel CLI (recommended):**

The command will display the YAML configuration to add to your Goose config file. **One-click install:** Click [here](goose://extension?cmd=npx\&arg=-y\&arg=mcp-remote\&arg=https%3A%2F%2Fmcp.onkernel.com%2Fmcp\&timeout=300\&id=kernel\&name=Kernel\&description=Access%20Kernel%27s%20cloud-based%20browsers%20via%20MCP) to install Kernel on Goose in one click.

#### Goose Desktop

1. Click `Extensions` in the sidebar of the Goose Desktop.
2. Click `Add custom extension`.
3. On the `Add custom extension` modal, enter:
4. Click `Save Changes` button.

#### Goose CLI

1. Run the following command:
2. Select `Add Extension` from the menu.
3. Choose `Command-line Extension`.
4. Follow the prompts:

### Visual Studio Code

**Using Kernel CLI (recommended):**

**Manual setup:** Add to your VS Code settings.json:

Or use the UI:

1. Press **⌘/Ctrl Shift P** → search **MCP: Add Server**.
2. Select **HTTP (HTTP or Server-Sent Events)**.
3. Enter: `https://mcp.onkernel.com/mcp`
4. Name the server **Kernel** → Enter.

### Windsurf

**Using Kernel CLI (recommended):**

**Manual setup:**

1. Press **⌘/Ctrl ,** to open settings.
2. Navigate **Cascade → MCP servers → View raw config**.
3. Paste:

4) On **Manage MCPs**, click **Refresh** to load Kernel MCP.

### Zed

**Using Kernel CLI (recommended):**

**Manual setup:**

1. Press **⌘/Ctrl ,** to open settings.
2. Paste:

### Smithery

You can connect directly to `https://mcp.onkernel.com/mcp`, or use Smithery as a proxy using its provided URL.

### Others

Many other MCP-capable tools accept:

Configure these values wherever the tool expects MCP server settings.

## Tools

### Browser Automation

### Profile Management

### App Management

### Documentation & Search

## Resources

## Prompts

## Troubleshooting

## Examples

### Invoke apps from anywhere

### Execute Playwright code dynamically

### Set up browser profiles for authentication

### Debug a browser session

----
url: https://www.kernel.sh/docs/apps/secrets
----

There are multiple ways to pass secrets and API keys to your Kernel app:

## [​](#1-deployment-environment-variables)1. Deployment environment variables

Deploy your app with secrets as [environment variables](https://www.kernel.sh/docs/apps/deploy#environment-variables). Your app can then access them at runtime. You can set environment variables in two ways:

* **`--env` flag**: Pass individual key-value pairs directly in the command
* **`--env-file` flag**: Load variables from a `.env` file

```
# Using --env flag for individual variables
kernel deploy my_app.ts --env OPENAI_API_KEY=sk-... --env ANTHROPIC_API_KEY=sk-ant-...

# Using --env-file to load from a file
kernel deploy my_app.ts --env-file .env

# Combine both approaches
kernel deploy my_app.ts --env-file .env --env OPENAI_API_KEY=sk-...
```

Then access the variables in your app:

```
import Anthropic from "@anthropic-ai/sdk";
import OpenAI from "openai";

app.action('ai-action', async (ctx: KernelContext) => {
  // Access API keys from environment variables
  const anthropic = new Anthropic({
    apiKey: process.env.ANTHROPIC_API_KEY,
  });

  const openai = new OpenAI({
    apiKey: process.env.OPENAI_API_KEY,
  });

  // Use the clients...
});
```

## [​](#2-runtime-variables)2. Runtime variables

For use cases where different API keys are needed per invocation (such as platforms using end-user keys), pass the secrets at runtime using the [payload parameter](https://www.kernel.sh/docs/apps/invoke#payload-parameter). Use encryption standards in your app to protect sensitive data.

```
import OpenAI from "openai";

app.action('ai-action', async (ctx: KernelContext, payload) => {
  // Decrypt the API key passed at runtime
  const apiKey = decrypt(payload.encryptedApiKey);

  const openai = new OpenAI({
    apiKey: apiKey,
  });

  // Use the client with the user's API key...
});
```

----
url: https://www.kernel.sh/docs/api-reference/browser-computer-controls/type-text-on-the-browser-instance
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.typeText('id', { text: 'text' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

type

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.typeText('id', { text: 'text' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-text)

text

string

required

Text to type on the browser instance

[​](#body-delay)

delay

integer

default:0

Delay in milliseconds between keystrokes

Required range

: `x >= 0`

#### Response

Text typed successfully

[Capture a screenshot of the browser instance](https://www.kernel.sh/docs/api-reference/browser-computer-controls/capture-a-screenshot-of-the-browser-instance)

[Previous](https://www.kernel.sh/docs/api-reference/browser-computer-controls/capture-a-screenshot-of-the-browser-instance)

[Press one or more keys on the host computer](https://www.kernel.sh/docs/api-reference/browser-computer-controls/press-one-or-more-keys-on-the-host-computer)

[Next](https://www.kernel.sh/docs/api-reference/browser-computer-controls/press-one-or-more-keys-on-the-host-computer)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/profiles/create-a-new-profile
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const profile = await client.profiles.create();

console.log(profile.id);
```

```
{
  "id": "<string>",
  "created_at": "2023-11-07T05:31:56Z",
  "name": "<string>",
  "updated_at": "2023-11-07T05:31:56Z",
  "last_used_at": "2023-11-07T05:31:56Z"
}
```

POST

/

profiles

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const profile = await client.profiles.create();

console.log(profile.id);
```

```
{
  "id": "<string>",
  "created_at": "2023-11-07T05:31:56Z",
  "name": "<string>",
  "updated_at": "2023-11-07T05:31:56Z",
  "last_used_at": "2023-11-07T05:31:56Z"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Body

application/json

Request body for creating a profile.

[​](#body-name)

name

string

Optional name of the profile. Must be unique within the organization.

#### Response

Profile created successfully

[List profiles](https://www.kernel.sh/docs/api-reference/profiles/list-profiles)

[Previous](https://www.kernel.sh/docs/api-reference/profiles/list-profiles)

[Get profile by ID or name](https://www.kernel.sh/docs/api-reference/profiles/get-profile-by-id-or-name)

[Next](https://www.kernel.sh/docs/api-reference/profiles/get-profile-by-id-or-name)

⌘I

----
url: https://www.kernel.sh/docs/apps/develop
----

In addition to our browser API, Kernel provides a code execution platform for deploying and invoking code. Typically, Kernel’s code execution platform is used for deploying and invoking browser automations or web agents. When using Kernel’s code execution platform, we co-locate your code with any Kernel browser environments you instantiate in your app. This solves common issues with browser connections over CDP:

## Apps, Actions, and Invocations

An `App` is a codebase deployed on Kernel. You can deploy any codebase in Typescript or Python on Kernel. An `Action` is an invokable method within an app. Actions allow your to register entry points or functions that can be triggered on-demand. Actions can call non-action methods. Apps can have multiple actions. An `Invocation` is a single execution of an action. Invocations can be triggered via API, scheduled as a job, or run on-demand.

## Getting started: create an app

First, install the Kernel SDK for your language:

Then create an app:

Then, define and register an action that you want to invoke.

## Registering actions

Action methods receive two parameters:

You can register actions using either approach:

### Inline definition (recommended)

### Define then register

This approach is better for larger apps, unit testing, and team collaboration since functions can be tested independently and reused across multiple actions.

## Environment variables

You can set environment variables when [deploying](https://www.kernel.sh/docs/apps/deploy#environment-variables) your app. They then can be accessed in the usual way:

## Return values

Action methods can return values, which will be included in the invocation’s final response.

The examples above show actions returning data.

## Building browser automations with Kernel apps

To implement a browser automation or web agent, instantiate an app and define an action that creates a Kernel browser.

## Next steps

Once you’re happy with your app, follow [these steps](https://www.kernel.sh/docs/apps/deploy) to deploy and invoke it on the Kernel platform.

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/stop-watching-a-directory
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.watch.stop('watch_id', { id: 'id' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

DELETE

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.watch.stop('watch_id', { id: 'id' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

#### Response

Watch stopped successfully

[Stream filesystem events for a watch](https://www.kernel.sh/docs/api-reference/browser-filesystem/stream-filesystem-events-for-a-watch)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/stream-filesystem-events-for-a-watch)

[Download a directory as a ZIP archive](https://www.kernel.sh/docs/api-reference/browser-filesystem/download-a-directory-as-a-zip-archive)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/download-a-directory-as-a-zip-archive)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/profiles/download-profile-archive
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.profiles.download('id_or_name');

console.log(response);

const content = await response.blob();
console.log(content);
```

```
"<string>"
```

GET

/

profiles

/

{id\_or\_name}

/

download

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.profiles.download('id_or_name');

console.log(response);

const content = await response.blob();
console.log(content);
```

```
"<string>"
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id-or-name)

id\_or\_name

string

required

Profile ID or name

#### Response

Profile ZIP archive

The response is of type `file`.

[Delete profile by ID or name](https://www.kernel.sh/docs/api-reference/profiles/delete-profile-by-id-or-name)

[Previous](https://www.kernel.sh/docs/api-reference/profiles/delete-profile-by-id-or-name)

[List auth connections](https://www.kernel.sh/docs/api-reference/managed-auth/list-auth-connections)

[Next](https://www.kernel.sh/docs/api-reference/managed-auth/list-auth-connections)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/profiles/list-profiles
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

// Automatically fetches more pages as needed.
for await (const profile of client.profiles.list()) {
  console.log(profile.id);
}
```

```
[
  {
    "id": "<string>",
    "created_at": "2023-11-07T05:31:56Z",
    "name": "<string>",
    "updated_at": "2023-11-07T05:31:56Z",
    "last_used_at": "2023-11-07T05:31:56Z"
  }
]
```

GET

/

profiles

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

// Automatically fetches more pages as needed.
for await (const profile of client.profiles.list()) {
  console.log(profile.id);
}
```

```
[
  {
    "id": "<string>",
    "created_at": "2023-11-07T05:31:56Z",
    "name": "<string>",
    "updated_at": "2023-11-07T05:31:56Z",
    "last_used_at": "2023-11-07T05:31:56Z"
  }
]
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Query Parameters

[​](#parameter-limit)

limit

integer

default:20

Limit the number of profiles to return.

Required range

: `1 <= x <= 100`

[​](#parameter-offset)

offset

integer

default:0

Offset the number of profiles to return.

Required range

: `x >= 0`

[​](#parameter-query)

query

string

Search profiles by name or ID.

#### Response

List of profiles

[​](#response-items-id)

id

string

required

Unique identifier for the profile

[​](#response-items-created-at)

created\_at

string\<date-time>

required

Timestamp when the profile was created

[​](#response-items-name-one-of-0)

name

string | null

Optional, easier-to-reference name for the profile

[​](#response-items-updated-at)

updated\_at

string\<date-time>

Timestamp when the profile was last updated

[​](#response-items-last-used-at)

last\_used\_at

string\<date-time>

Timestamp when the profile was last used

[Flush all idle browsers in the pool](https://www.kernel.sh/docs/api-reference/browser-pools/flush-all-idle-browsers-in-the-pool)

[Previous](https://www.kernel.sh/docs/api-reference/browser-pools/flush-all-idle-browsers-in-the-pool)

[Create a new profile](https://www.kernel.sh/docs/api-reference/profiles/create-a-new-profile)

[Next](https://www.kernel.sh/docs/api-reference/profiles/create-a-new-profile)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browsers/update-browser-session
----

Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (1920x1080\@25). For GPU images, the default is 1920x1080\@60. Arbitrary viewport dimensions and refresh rates are accepted. Known-good presets include: 2560x1440\@10, 1920x1080\@25, 1920x1200\@25, 1440x900\@25, 1280x800\@60, 1024x768\@60, 1200x800\@60. For GPU images, recommended presets use one of these resolutions with refresh rates 60, 30, 25, or 10: 800x600, 960x720, 1024x576, 1024x768, 1152x648, 1200x800, 1280x720, 1368x768, 1440x900, 1600x900, 1920x1080, 1920x1200, 390x844, 360x250, 768x1024, 800x1600. Viewports outside this list may exhibit unstable live view or recording behavior. If refresh\_rate is not provided, it will be automatically determined based on the resolution (higher resolutions use lower refresh rates to keep bandwidth reasonable).

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-directory
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.deleteDirectory('id', { path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

delete\_directory

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.deleteDirectory('id', { path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

#### Response

Directory deleted

[Delete a file](https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-file)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-file)

[Set file or directory permissions/ownership](https://www.kernel.sh/docs/api-reference/browser-filesystem/set-file-or-directory-permissionsownership)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/set-file-or-directory-permissionsownership)

Ctrl+I

----
url: https://www.kernel.sh/docs/apps/deploy
----

Kernel’s app deployment process is as simple as it is fast. There are no configuration files to manage or complex CI/CD pipelines. Once you deploy an app on Kernel, you can schedule its actions on a job or run them from other contexts. You can even run actions multiple times in parallel.

## [​](#deploy-the-app)Deploy the app

### [​](#from-local-directory)From local directory

Use our CLI from the root directory of your project:

```
kernel deploy <entrypoint_file_name>
```

#### [​](#notes)Notes

* The `entrypoint_file_name` is the file name where you [defined](https://www.kernel.sh/docs/apps/develop) your app.
* Include a `.gitignore` file to exclude dependency folders like `node_modules` and `.venv`.

### [​](#from-github)From GitHub

You can deploy a Kernel app directly from a public or private GitHub repository using the Kernel CLI. No need to clone or manually push code.

```
kernel deploy github \
  --url https://github.com/<owner>/<repo> \
  --ref <branch|tag|commit> \
  --entrypoint <path/to/entrypoint> \
  [--path <optional/subdir>] \
  [--github-token <token>] \
  [--env KEY=value ...] \
  [--env-file .env] \
  [--version latest] \
  [--force]
```

#### [​](#notes-2)Notes

* **`--path` vs `--entrypoint`:** Use `--path` to specify a subdirectory within the repo (useful for monorepos), and `--entrypoint` for the path to your app’s entry file relative to that directory (or repo root if no `--path` is specified).
* The CLI automatically downloads and extracts the GitHub source code and uploads your app for deployment.
* For private repositories, provide a `--github-token` or set the `GITHUB_TOKEN` environment variable.

## [​](#environment-variables)Environment variables

You can set environment variables for your app using the `--env` flag. For example:

```
kernel deploy my_app.ts --env MY_ENV_VAR=my_value # Can add multiple env vars delimited by space
```

## [​](#deployment-notes)Deployment notes

* **The dependency manifest (`package.json` for JS/TS, `pyproject.toml` for Python) must be present in the root directory of your project.**
* **For JS/TS apps, set `"type": "module"` in your `package.json`.**
* View deployment logs using: `kernel deploy logs <deployment_id> --follow`
* If you encounter a 500 error during deployment, verify that your entrypoint file name and extension are correct (e.g., `app.py` not `app` or `app.js`).
* Kernel assumes the root directory contains at least this file structure:

```
project-root/
  ├─ .gitignore # Exclude dependency folders like node_modules
  ├─ my_app.ts # Entrypoint file (can be located in a subdirectory, e.g. src/my_app.ts)
  ├─ package.json
  ├─ tsconfig.json # If using TypeScript
  └─ bun.lock | package-lock.json | pnpm-lock.yaml # One of these lockfiles
```

```
# Successful deployment CLI output
SUCCESS  Compressed files
SUCCESS  Deployment successful
SUCCESS  App "my_app.ts" deployed with action(s): [my-action]
INFO  Invoke with: kernel invoke my-app my-action --payload '{...}'
SUCCESS  Total deployment time: 2.78s
```

Once deployed, you can [invoke](https://www.kernel.sh/docs/apps/invoke) your app from anywhere.

----
url: https://www.kernel.sh/docs/api-reference/managed-auth/submit-field-values
----

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Auth connection ID

#### Body

application/json

Request to submit field values, click an SSO button, or select an MFA method. Provide exactly one of fields, sso\_button\_selector, or mfa\_option\_id.

[​](#body-fields)

fields

object

Map of field name to value

Show child attributes

Example:

```
{
  "email": "user@example.com",
  "password": "secret"
}
```

[​](#body-sso-button-selector)

sso\_button\_selector

string

Optional XPath selector if user chose to click an SSO button instead

Example:

`"xpath=//button[contains(text(), 'Continue with Google')]"`

[​](#body-mfa-option-id)

mfa\_option\_id

string

Optional MFA option ID if user selected an MFA method

Example:

`"sms"`

#### Response

Submission accepted for processing

Response from submitting field values

[​](#response-accepted)

accepted

boolean

required

Whether the submission was accepted for processing

----
url: https://www.kernel.sh/docs/browsers/bot-detection/overview
----

Automating the web as a browser agent is hard. Modern websites deploy increasingly sophisticated bot detection systems to prevent fraud, abuse, and denial-of-service attacks. Even if you have explicit permission to automate — for example, QA’ing your own site or performing actions on behalf of users with their consent — these systems often assume any automated browser is hostile. Kernel provides tools to help with these challenges. Under the hood, our browsers are optimized for realistic environments. **Everything we do is open source and inspectable — you can view our build configurations and runtime layers [here](https://github.com/onkernel/kernel-images).** This guide explains how bot detection works at a high level, common pitfalls to avoid, and how Kernel’s features can help your automations run reliably.

## How Bot Detection Works

Most detection systems look for inconsistencies between how a real user’s browser behaves and how an automated one does. Common giveaways include:

* **IP addresses**: IPs from data centers (AWS, GCP, Azure)
* **Browser environment**: unusual viewport sizes, incorrect timezones, or missing APIs
* **Automation frameworks**: traces of Playwright, Puppeteer, or Chrome DevTools Protocol (CDP) connections
* **Headless browsers** — browsers started without a visible window expose subtle differences (rendering, GPU, fonts)
* **Typing/clicking signals** — identical cursor paths, uniform typing speeds, or rapid mouse movements
* **Metadata** — mismatched cookies, inconsistent user-agent strings

These systems are heuristic and probabilistic — small mismatches can still trigger blocks. The goal isn’t to “beat” detection but rather emulate the real-world conditions of a normal browser session.

## Kernel Features That Help

### [Stealth Mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth)

A basic configuration that launches Kernel’s browser through a residential proxy and integrates a Google [reCAPTCHA solver](https://www.google.com/recaptcha/api2/demo).

### [Configurable Proxies](https://www.kernel.sh/docs/proxies/overview)

Bring your own proxy network or use Kernel’s managed pool (selectable down to ZIP-code level). If needed, use the same IP to reduce detection and allow for regional testing or QA.

### [Profiles](https://www.kernel.sh/docs/auth/profiles)

Profiles persist cookies, local storage, and session data between runs. Combined with a fixed proxy, this mimics a returning user. We recommend using them to persist authenticated states and reduce CAPTCHAs.

### [Browser Pools](https://www.kernel.sh/docs/browsers/pools/overview)

Browser pools let you reuse browsers across multiple visits to the same website, which introduces consistency with respect to the IP address. Since IP addresses are one of the main components of fingerprinting used by modern bot detection systems, browser pools drastically increase your chances of avoiding detection.

### [Playwright Execution API](https://www.kernel.sh/docs/browsers/playwright-execution)

Executes Playwright scripts in the same VM as the browser, ensuring headers, user-agent strings, and environment match. Kernel automatically applies Patchright to remove automation fingerprints, including headless indicators.

### [Computer Controls API](https://www.kernel.sh/docs/browsers/computer-controls)

Controls the browser without using the Chrome DevTools Protocol (CDP), which can reduce bot detection signals. Emulates native keyboard and mouse input directly at the OS level.

## Getting Started

Before you start automating your workflow, we recommend that you manually test your website to understand how it behaves with Kernel’s browsers. Here’s how to do that:

1. **Launch a browser from the [Kernel dashboard](https://dashboard.onkernel.com/browsers).** This opens a Kernel browser instance in a clean virtual machine.
2. **Navigate to the target website** and perform the same actions you plan to automate — logging in, filling forms, loading dashboards, etc.
3. **Observe potential friction points:**
4. **Adjust environment settings** — such as proxy configurations — until the manual session works smoothly.

Once you have a stable baseline, replicate those conditions in your automations.

## Recommended Practices

| Category                | Recommendation                                                                                                                             |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **Viewport & Display**  | Use Kernel’s default viewport — we’ve tuned it to mirror realistic device profiles.                                                        |
| **Headless Mode**       | Avoid headless mode. Kernel runs full, rendered browsers by default.                                                                       |
| **User Agent Headers**  | Don’t override headers manually. Let Kernel manage them for minimize mismatches.                                                           |
| **Execution Method**    | Prefer our **Playwright Execution API** or **Computer Controls API** over self-hosted Playwright/Puppeteer.                                |
| **Session Persistence** | Use **Profiles** to retain cookies and local storage between sessions.                                                                     |
| **Typing & Scrolling**  | Add natural variation to interaction timing.                                                                                               |
| **Rate Limits**         | Many sites monitor request frequency; rapid / concurrent actions can trigger blocking.                                                     |
| **Network Identity**    | Use stable IP addresses, especially if logging in.                                                                                         |
| **Extensions**          | Use the [Extensions API](https://www.kernel.sh/docs/browsers/extensions) carefully — each adds its own fingerprint, which can be detected. |

## Conclusion

Bot detection is nuanced and constantly evolving. **Kernel provides the building blocks — browsers, proxies, profiles, and APIs — to help agents operate safely and reliably.** Our mission is to help developers automate the web on behalf of users and with their consent, while respecting the systems that keep the internet secure.

----
url: https://www.kernel.sh/docs/browsers/bot-detection/stealth
----

Kernel browsers can be configured to `stealth` mode, which automatically adds our recommended proxy to your browser instances. It also adds a `reCAPTCHA solver` to the browser, so it automatically solves [reCAPTCHAs](https://www.google.com/recaptcha/api2/demo) on your behalf. To turn on stealth mode, set its flag when instantiating Kernel browsers:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create({
  stealth: true,
});
```

If you’re looking for proxy-level configuration with Kernel browsers, see [Proxies](https://www.kernel.sh/docs/proxies/overview).

## [​](#captcha-handling-behavior)CAPTCHA Handling Behavior

Below are tips for working with Kernel’s Stealth Mode auto-CAPTCHA solver across different challenge types and automation frameworks.

### [​](#anthropic-computer-use)Anthropic Computer Use

Anthropic Computer Use stops when it encounters a CAPTCHA. Use Kernel’s auto-CAPTCHA solver by adding this to your prompt: `"If you see a CAPTCHA or similar test, just wait for it to get solved automatically by the browser."`

### [​](#cloudflare-challenge)Cloudflare Challenge

When encountering a Cloudflare challenge, our auto-CAPTCHA solver will attempt to handle it. Once the “Ready” message appears on the screen, continue with your intended browser actions (e.g., entering credentials and submitting a login attempt).

After the “Ready” message appears, don’t click the Cloudflare CAPTCHA checkbox — this can interfere with the solver.

----
url: https://www.kernel.sh/docs/integrations/computer-use/openai
----

[Computer Use](https://openai.com/index/computer-using-agent/) is OpenAI’s feature that enables AI models to interact with computers the way humans do—by looking at screens, moving cursors, clicking buttons, and typing text. This powerful feature allows AI agents to control web browsers, navigate interfaces, and perform complex tasks across applications. By integrating Computer Use with Kernel, you can run these AI-powered browser automations on cloud-hosted infrastructure, eliminating the need for local browser management and enabling scalable, reliable AI agents.

## [​](#quick-setup-with-our-computer-use-example-app)Quick setup with our Computer Use example app

Get started quickly with our Kernel app template that includes a pre-configured Computer Use integration:

```
kernel create --name my-computer-use-app --template cua
```

Choose `TypeScript` or `Python` as the programming language. Then follow the [Quickstart guide](https://www.kernel.sh/docs/quickstart) to deploy and run your Computer Use automation on Kernel’s infrastructure.

## [​](#benefits-of-using-kernel-with-computer-use)Benefits of using Kernel with Computer Use

* **No local browser management**: Run Computer Use automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel for concurrent automations
* **Stealth mode**: Built-in anti-detection features for web interactions
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your automations with real-time browser viewing

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Computer Use app to Kernel

----
url: https://www.kernel.sh/docs/browsers/computer-controls
----

Use OS-level controls to move and click the mouse, type and press keys, scroll, drag, and capture screenshots from a running browser session. Both `moveMouse` and `dragMouse` use human-like [Bézier curves](https://en.wikipedia.org/wiki/B%C3%A9zier_curve) by default.

## Click the mouse

Simulate mouse clicks at specific coordinates. You can select the button, click type (down, up, click), number of clicks, and optional modifier keys to hold.

## Move the mouse

Move the cursor to specific screen coordinates. By default, the cursor follows a human-like Bezier curve path instead of teleporting instantly. You can control this with `smooth` and `duration_ms`.

| Parameter     | Type    | Default | Description                                                                                                |
| ------------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------- |
| `x`           | integer | —       | X coordinate to move the cursor to                                                                         |
| `y`           | integer | —       | Y coordinate to move the cursor to                                                                         |
| `smooth`      | boolean | `true`  | Use human-like Bezier curve path instead of instant teleport                                               |
| `duration_ms` | integer | auto    | Target duration in milliseconds for smooth movement (50–5000). Omit for automatic timing based on distance |
| `hold_keys`   | array   | —       | Modifier keys to hold during the move                                                                      |

### Smooth vs instant movement

Try it yourself — open [live view](https://www.kernel.sh/docs/browsers/live-view) and paste this (requires CLI v0.15.4+ — run `kernel upgrade` to update):

## Take screenshots

Capture a full-screen PNG or a specific region.

## Type text

Type literal text, optionally with a delay in milliseconds between keystrokes.

## Press keys

Press one or more key symbols (including combinations like “Ctrl+t” or “Ctrl+Shift+Tab”). Optionally hold modifiers and/or set a duration to hold keys down.

Scroll the mouse wheel at a specific position. Positive `delta_y` scrolls down; negative scrolls up. Positive `delta_x` scrolls right; negative scrolls left.

## Drag the mouse

Drag by pressing a button, moving along a path of points, then releasing. By default, drag movement uses human-like Bezier curves between waypoints. Set `smooth: false` to use linear interpolation with `steps_per_segment` and `step_delay_ms` instead.

| Parameter           | Type    | Default | Description                                                                                                                             |
| ------------------- | ------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `path`              | array   | —       | Ordered list of `[x, y]` coordinate pairs to move through (minimum 2 points)                                                            |
| `button`            | string  | `left`  | Mouse button: `left`, `middle`, or `right`                                                                                              |
| `smooth`            | boolean | `true`  | Use human-like Bezier curves between waypoints. When `true`, `steps_per_segment` and `step_delay_ms` are ignored                        |
| `duration_ms`       | integer | auto    | Target duration in milliseconds for the entire drag when `smooth=true` (50–10000). Omit for automatic timing based on total path length |
| `delay`             | integer | `0`     | Delay in milliseconds between button down and starting to move                                                                          |
| `steps_per_segment` | integer | `10`    | Number of interpolation steps per path segment (only when `smooth=false`)                                                               |
| `step_delay_ms`     | integer | `50`    | Delay in milliseconds between steps (only when `smooth=false`)                                                                          |
| `hold_keys`         | array   | —       | Modifier keys to hold during the drag                                                                                                   |

### Smooth vs linear drag

----
url: https://www.kernel.sh/docs/api-reference/browser-processes/stream-process-stdout-via-sse
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.process.stdoutStream(
  '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
  { id: 'id' },
);

console.log(response.data_b64);
```

```
{
  "stream": "stdout",
  "data_b64": "<string>",
  "event": "exit",
  "exit_code": 123
}
```

stdout

/

stream

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.process.stdoutStream(
  '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
  { id: 'id' },
);

console.log(response.data_b64);
```

```
{
  "stream": "stdout",
  "data_b64": "<string>",
  "event": "exit",
  "exit_code": 123
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

#### Response

SSE stream of process output and lifecycle events

SSE payload representing process output or lifecycle events.

[​](#response-stream)

stream

enum\<string>

Source stream of the data chunk.

Available options

:

`stdout`,

`stderr`

[​](#response-data-b64)

data\_b64

string

Base64-encoded data from the process stream.

[​](#response-event)

event

enum\<string>

Lifecycle event type.

Available options

:

`exit`

[​](#response-exit-code)

exit\_code

integer

Exit code when the event is "exit".

[Get process status](https://www.kernel.sh/docs/api-reference/browser-processes/get-process-status)

[Previous](https://www.kernel.sh/docs/api-reference/browser-processes/get-process-status)

[Write to process stdin](https://www.kernel.sh/docs/api-reference/browser-processes/write-to-process-stdin)

[Next](https://www.kernel.sh/docs/api-reference/browser-processes/write-to-process-stdin)

Ctrl+I

----
url: https://www.kernel.sh/docs/apps/invoke
----

## [​](#via-api)Via API

You can invoke your app by making a `POST` request to Kernel’s API or via the CLI. Both support passing a payload. **For automations and agents that take longer than 100 seconds, use [async invocations](https://www.kernel.sh/docs/apps/invoke#asynchronous-invocations).**

Synchronous invocations time out after 100 seconds.

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const invocation = await kernel.invocations.create({
  action_name: 'analyze',
  app_name: 'my-app',
  version: '1.0.0',
});

console.log(invocation.id);
```

### [​](#asynchronous-invocations)Asynchronous invocations

For long running jobs, use asynchronous invocations to trigger Kernel actions without waiting for the result. You can then stream real-time [status updates](https://www.kernel.sh/docs/apps/status#streaming-status-updates) for the result.

Asynchronous invocations time out after 15 minutes by default but can be configured to last up to 1 hour by setting the optional `async_timeout_seconds` parameter during invocation.

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const invocation = await kernel.invocations.create({
  async: true,
  action_name: 'analyze',
  app_name: 'my-app',
  version: '1.0.0',
});

console.log(invocation.id);
```

## [​](#via-cli)Via CLI

Invoke an app action immediately via the CLI:

```
kernel invoke <app_name> <action_name>
```

### [​](#payload-parameter)Payload parameter

`--payload` allows you to invoke the action with specified parameters. This enables your action to receive and handle dynamic inputs at runtime. For example:

Payloads are stringified JSON and have a maximum size of 4.5 MB.

```
kernel invoke <app_name> <action_name>
    --payload '{"tshirt_size": "small", "color": "black", "shipping_address": "2 Mint Plz, San Francisco CA 94103"}'
```

See [here](https://www.kernel.sh/docs/apps/develop#parameters) to learn how to access the payload in your action method.

### [​](#return-values)Return values

If your action specifies a [return value](https://www.kernel.sh/docs/apps/develop#return-values), the invocation returns its value once it completes. (The Kernel CLI uses asynchronous invocations under the hood)

----
url: https://www.kernel.sh/docs/quickstart
----

## Getting started

This quickstart guide will help you deploy and invoke your first browser automation on Kernel. You’ll create a simple automation using Playwright, Computer Use, or a web agent framework like Browser Use.

## Prerequisites

> **Note:** You can also deploy and invoke apps using the [Kernel MCP server](https://www.kernel.sh/docs/reference/mcp-server) from AI assistants (Cursor, Goose, Claude, etc.).

## 1. Install the Kernel CLI

Verify the installation exists:

## 2. Create a new Kernel app

## 3. Authenticate with Kernel

The easiest way to authenticate is using OAuth:

This will open your browser to complete the authentication flow. Your credentials will be securely stored and automatically refreshed.

## 4. Deploy the sample app on Kernel

## 5. Invoke the app

## Next steps

Nice work! With Kernel, you:

1. Developed an app that uses Playwright, Computer Use, or a web agent framework like Browser Use
2. Deployed and invoked it in the cloud

You can now update your browser automation with your own logic and deploy it again. Install our [MCP server](https://www.kernel.sh/docs/reference/mcp-server) to give your coding agent our `search_docs` tool.

## Sample apps reference

These are the sample apps currently available when you run `kernel create`:

| Template                   | Description                                      | Framework                  |
| -------------------------- | ------------------------------------------------ | -------------------------- |
| **sample-app**             | Implements a basic Kernel app                    | Playwright                 |
| **captcha-solver**         | Demo of Kernel’s auto-CAPTCHA solving capability | Playwright                 |
| **browser-use**            | Implements Browser Use SDK                       | Browser Use                |
| **stagehand**              | Implements the Stagehand v3 SDK                  | Stagehand                  |
| **anthropic-computer-use** | Implements an Anthropic computer use agent       | Anthropic Computer Use API |
| **openai-computer-use**    | Implements an OpenAI computer use agent          | OpenAI Computer Use API    |
| **gemini-computer-use**    | Implements a Gemini computer use agent           | Gemini Computer Use API    |
| **openagi-computer-use**   | Implements an OpenAGI computer use agent         | OpenAGI Computer Use API   |
| **magnitude**              | Implements the Magnitude.run SDK                 | Magnitude.run              |

----
url: https://www.kernel.sh/docs/apps/logs
----

## [​](#via-api)Via API

After you [invoke](https://www.kernel.sh/docs/apps/invoke) an action, you can stream the invocation’s logs in real time:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const logs = await kernel.invocations.follow(invocation_id);
```

Log lines will be truncated to 64KiB. For large payloads write data to external storage and log a reference instead.

### [​](#example)Example

Here’s an example showing how to handle streaming logs:

Typescript/Javascript

```
const follow = await kernel.invocations.follow(invocation.id);

for await (const evt of follow) {
  if (evt.event === 'log') {
    console.log(`[${evt.timestamp}] ${evt.message}`);
  } else if (evt.event === 'error') {
    console.error('Error:', evt.error.message);
    break;
  } else if (evt.event === 'invocation_state') {
    if (evt.invocation.status === 'succeeded' || evt.invocation.status === 'failed') {
      break;
    }
  }
}
```

## [​](#via-cli)Via CLI

You can also stream the logs to your terminal via the CLI:

```
kernel logs <app_name> --follow
```

If you don’t specify `--follow`, the logs will print to the terminal until 3 seconds of inactivity and then stops. You can get logs for a specific invocation by adding:

```
-i --invocation <invocation id>    Show logs for a specific invocation of the app.
```

----
url: https://www.kernel.sh/docs/api-reference/profiles/get-profile-by-id-or-name
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const profile = await client.profiles.retrieve('id_or_name');

console.log(profile.id);
```

```
{
  "id": "<string>",
  "created_at": "2023-11-07T05:31:56Z",
  "name": "<string>",
  "updated_at": "2023-11-07T05:31:56Z",
  "last_used_at": "2023-11-07T05:31:56Z"
}
```

GET

/

profiles

/

{id\_or\_name}

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const profile = await client.profiles.retrieve('id_or_name');

console.log(profile.id);
```

```
{
  "id": "<string>",
  "created_at": "2023-11-07T05:31:56Z",
  "name": "<string>",
  "updated_at": "2023-11-07T05:31:56Z",
  "last_used_at": "2023-11-07T05:31:56Z"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id-or-name)

id\_or\_name

string

required

Profile ID or name

#### Response

Profile details

[Create a new profile](https://www.kernel.sh/docs/api-reference/profiles/create-a-new-profile)

[Previous](https://www.kernel.sh/docs/api-reference/profiles/create-a-new-profile)

[Delete profile by ID or name](https://www.kernel.sh/docs/api-reference/profiles/delete-profile-by-id-or-name)

[Next](https://www.kernel.sh/docs/api-reference/profiles/delete-profile-by-id-or-name)

Ctrl+I

----
url: https://www.kernel.sh/docs/browsers/extensions
----

Kernel’s browsers support running with custom Chrome extensions. Chrome extensions must be unpacked and can be uploaded to Kernel via the CLI or API.

## Uploading extensions

Here is a simple example of an unpacked extension:

Once these files are in place, you can upload them to Kernel via the CLI (or [API](https://www.kernel.sh/docs/api-reference/extensions/upload-a-browser-extension)):

Extensions uploaded to Kernel are assigned a random ID, but you can also give them a name for easier reference. This name must be unique within your organization.

## Using extensions in a browser

Passing the extension name or ID to the `create` method will load it into the browser.

## Using extensions directly from the Chrome Web Store

Kernel’s CLI offers a command for fetching and unpacking extensions directly from the Chrome Web Store. Simply pass the URL of the extension you want to download and the CLI will download the extension and unpack it into the specified directory.

From here you can upload the extension to Kernel as normal.

## Loading an extension into a running browser

If you have a browser running and would like to load an extension into it after the browser session has started, Kernel also allows you to do that via the CLI (or [API](https://www.kernel.sh/docs/api-reference/browsers/ad-hoc-upload-one-or-more-unpacked-extensions-to-a-running-browser-instance)):

## Extensions requiring enterprise policies

For a complete list of available extension settings and policies, refer to the [Chrome Enterprise Policy documentation](https://chromeenterprise.google/policies/extension-settings/).

### Uploading extensions requiring enterprise policies

Some Chrome extensions require elevated permissions that Chrome will only grant when the extension is installed via enterprise policies. These extensions cannot be loaded with the standard `--load-extension` flag and require special handling.

### What are enterprise policy extensions?

Extensions that require enterprise policies typically:

Common examples include extensions for network filtering, request signing, or advanced content modification.

### Required files for upload

When uploading an extension that requires enterprise policies to Kernel, your extension directory or zip file must include:

1. **Extension source files** - Your `manifest.json` and all extension code (background scripts, content scripts, etc.)
2. **`update.xml`** - A Chrome update manifest that points to the `.crx` file location
3. **`.crx` file** - The signed and packed extension file

### Automatic detection and validation

Kernel automatically detects extensions that require enterprise policies by analyzing the `manifest.json` file during upload. No manual configuration is needed. **Detection process:**

1. You upload an extension via CLI or API
2. Kernel scans the `manifest.json` for permissions like `webRequestBlocking`
3. If enterprise policies are required, Kernel validates the required files are present

### How it works

Once you successfully upload an enterprise policy extension, Kernel handles the rest automatically:

1. **Upload** - You upload your extension with all required files
2. **Detection** - Kernel detects the enterprise policy requirement from the manifest
3. **Policy configuration** - Extension is automatically added to `ExtensionInstallForcelist`
4. **File serving** - The kernel-images server serves update files at `http://127.0.0.1:10001/extensions/{extension-id}/update.xml`
5. **Installation** - Chrome installs the extension via enterprise policy when the browser starts

No additional HTTP server or manual policy configuration is needed. The extension works seamlessly in any browser session that it’s uploaded to.

----
url: https://www.kernel.sh/docs/browsers/create-a-browser
----

Kernel browsers were designed to be lightweight and fast. Your agent can quickly create them on-demand and tear them down as soon as it is done using them. They can be used as part of the Kernel [app platform](https://www.kernel.sh/docs/apps/develop) or connected to from another service with the Chrome DevTools Protocol.

## [​](#1-create-a-kernel-browser)1. Create a Kernel browser

First, install the Kernel SDK:

* Typescript/Javascript: `npm install @onkernel/sdk`
* Python: `pip install kernel`

Use our SDK to create a browser:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create();
console.log(kernelBrowser.session_id);
```

## [​](#2-connect-over-cdp)2. Connect over CDP

Then, you can connect to the browser with any Chrome DevTools Protocol framework, such as Playwright or Puppeteer. You can also use our [Computer Controls API](https://www.kernel.sh/docs/browsers/computer-controls) to control the browser’s mouse and keyboard without using a CDP connection. This is useful for vision-based LLM loops like [Claude Computer Use](https://www.kernel.sh/docs/integrations/computer-use/anthropic).

```
import { chromium } from 'playwright';

// Playwright
const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url);

// Or with Puppeteer
import puppeteer from 'puppeteer';

const browser = await puppeteer.connect({
  browserWSEndpoint: kernelBrowser.cdp_ws_url,
  defaultViewport: null, // Optional: inherit viewport from the browser
});
```

## [​](#3-tear-it-down)3. Tear it down

When you’re finished with the browser, you can delete it:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

await kernel.browsers.deleteByID(kernelBrowser.session_id);
```

Browsers automatically delete after a timeout (default 60 seconds) if they don’t receive a CDP or live view connection. You can [configure this timeout](https://www.kernel.sh/docs/browsers/termination#automatic-deletion-via-timeout) when creating the browser.

## [​](#full-example)Full example

Once you’ve connected to the Kernel browser, you can do anything with it.

Kernel browsers launch with a default context and page. Make sure to access the [existing context and page](https://playwright.dev/docs/api/class-browsertype#browser-type-connect-over-cdp) (`contexts()[0]` and `pages()[0]`), rather than trying to create a new one.

```
import Kernel from '@onkernel/sdk';
import { chromium } from 'playwright';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create();
const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url);

try {
  const context = browser.contexts()[0] || (await browser.newContext());
  const page = context.pages()[0] || (await context.newPage());
  await page.goto('https://www.onkernel.com');
  const title = await page.title();
} catch (error) {
  console.error(error);
} finally {
  await browser.close();
  await kernel.browsers.deleteByID(kernelBrowser.session_id);
}
```

----
url: https://www.kernel.sh/docs/integrations/overview
----

Kernel’s browsers are compatible with all browser and Computer Use frameworks.

## [​](#universal-cdp-compatibility)Universal CDP compatibility

Kernel browsers work with any framework or tool that supports the Chrome DevTools Protocol (CDP). This means you can:

* **Use any agent framework**: Integrate with popular frameworks like Browser Use, Stagehand, Playwright, Puppeteer, Selenium, and more
* **Connect via CDP**: All browsers expose a CDP WebSocket URL for direct connection
* **No vendor lock-in**: Switch between frameworks or use multiple frameworks simultaneously
* **Standard protocols**: Built on open standards that work with the entire browser automation ecosystem

## [​](#computer-use)Computer Use

For vision-language models (VLMs) that predict browser actions from screenshots, Kernel provides [Computer Controls APIs](https://www.kernel.sh/docs/browsers/computer-controls) that enable direct mouse, keyboard, and screen interactions. These low-level controls let you:

* Capture screenshots to send to your VLM
* Execute predicted actions (clicks, typing, scrolling, dragging)
* Build custom agentic loops with any VLM provider

This approach works with any computer use model, including Anthropic Claude, OpenAI CUA, Google Gemini, and others.

## [​](#popular-framework-integrations)Popular Framework Integrations

Kernel provides detailed guides for popular agent frameworks:

* **[Agent Browser](https://www.kernel.sh/docs/integrations/agent-browser)** - Browser automation CLI for AI agents
* **[Browser Use](https://www.kernel.sh/docs/integrations/browser-use)** - AI browser agent framework
* **[Claude Agent SDK](https://www.kernel.sh/docs/integrations/claude-agent-sdk)** - Run Claude Agent SDK automations in cloud browsers
* **[Stagehand](https://www.kernel.sh/docs/integrations/stagehand)** - AI browser automation with natural language
* **[Computer Use (Anthropic)](https://www.kernel.sh/docs/integrations/computer-use/anthropic)** - Claude’s computer use capability
* **[Computer Use (OpenAI)](https://www.kernel.sh/docs/integrations/computer-use/openai)** - OpenAI’s computer use capability
* **[Computer Use (Gemini)](https://www.kernel.sh/docs/integrations/computer-use/gemini)** - Gemini’s computer use capability
* **[Computer Use (OpenAGI)](https://www.kernel.sh/docs/integrations/computer-use/openagi)** - OpenAGI’s computer use capability
* **[Computer Use (Yutori)](https://www.kernel.sh/docs/integrations/computer-use/yutori)** - Yutori n1 pixels-to-actions model
* **[Laminar](https://www.kernel.sh/docs/integrations/laminar)** - Observability and tracing for AI browser automations
* **[Magnitude](https://www.kernel.sh/docs/integrations/magnitude)** - Vision-focused browser automation framework
* **[Notte](https://www.kernel.sh/docs/integrations/notte)** - AI agent framework for browser automation
* **[Val Town](https://www.kernel.sh/docs/integrations/valtown)** - Serverless function runtime
* **[Vercel](https://github.com/onkernel/vercel-template)** - Deploy browser automations to Vercel
* **[Web Bot Authentication](https://www.kernel.sh/docs/browsers/bot-detection/web-bot-auth)** - Create signed Chrome extensions for web bot authentication
* **[1Password](https://www.kernel.sh/docs/integrations/1password)** - Use credentials from your 1Password vaults for Managed Auth

## [​](#custom-integrations)Custom Integrations

Kernel works with any tool that supports CDP. Check out our [browser creation guide](https://www.kernel.sh/docs/browsers/create-a-browser) to learn how to connect any other agent framework.

----
url: https://www.kernel.sh/docs/api-reference/browser-computer-controls/read-text-from-the-clipboard-on-the-browser-instance
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.computer.readClipboard('id');

console.log(response.text);
```

```
{
  "text": "<string>"
}
```

read

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.computer.readClipboard('id');

console.log(response.text);
```

```
{
  "text": "<string>"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Response

Clipboard content read successfully

[​](#response-text)

text

string

required

Current clipboard text content

[Set cursor visibility](https://www.kernel.sh/docs/api-reference/browser-computer-controls/set-cursor-visibility)

[Previous](https://www.kernel.sh/docs/api-reference/browser-computer-controls/set-cursor-visibility)

[Write text to the clipboard on the browser instance](https://www.kernel.sh/docs/api-reference/browser-computer-controls/write-text-to-the-clipboard-on-the-browser-instance)

[Next](https://www.kernel.sh/docs/api-reference/browser-computer-controls/write-text-to-the-clipboard-on-the-browser-instance)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-asynchronously
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.process.spawn('id', { command: 'command' });

console.log(response.pid);
```

```
{
  "process_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "pid": 123,
  "started_at": "2023-11-07T05:31:56Z"
}
```

spawn

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.process.spawn('id', { command: 'command' });

console.log(response.pid);
```

```
{
  "process_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "pid": 123,
  "started_at": "2023-11-07T05:31:56Z"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

[​](#body-allocate-tty)

allocate\_tty

boolean

default:false

Allocate a pseudo-terminal (PTY) for interactive shells.

[​](#body-rows)

rows

integer

Initial terminal rows. Only used when allocate\_tty is true.

Required range

: `1 <= x <= 65535`

[​](#body-cols)

cols

integer

Initial terminal columns. Only used when allocate\_tty is true.

Required range

: `1 <= x <= 65535`

#### Response

Spawned

Information about a spawned process.

[​](#response-process-id)

process\_id

string\<uuid>

Server-assigned identifier for the process.

[​](#response-pid)

pid

integer

OS process ID.

[​](#response-started-at)

started\_at

string\<date-time>

Timestamp when the process started.

[Execute a command synchronously](https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-synchronously)

[Previous](https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-synchronously)

[Get process status](https://www.kernel.sh/docs/api-reference/browser-processes/get-process-status)

[Next](https://www.kernel.sh/docs/api-reference/browser-processes/get-process-status)

Ctrl+I

----
url: https://www.kernel.sh/docs/browsers/live-view
----

Humans-in-the-loop can access the live view of Kernel browsers in real-time to resolve errors or take unscripted actions. To access the live view, visit the `browser_live_view_url` provided when you create a Kernel browser:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const browser = await kernel.browsers.create();
console.log(browser.browser_live_view_url);
```

## [​](#query-parameters)Query parameters

The `browser_live_view_url` supports additional query parameters to customize the live view:

* `readOnly` (bool): when set to `true`, the view will be non-interactive.

Example:

```
https://api.onkernel.com/browser/live/<TOKEN>?readOnly=true
```

## [​](#embedding-in-an-iframe)Embedding in an iframe

The live view URL can be embedded in an iframe to integrate the browser view into your own application or dashboard.

```
<iframe src={browser.browser_live_view_url}></iframe>
```

## [​](#kiosk-mode)Kiosk mode

Kiosk mode provides a fullscreen live view experience without browser UI elements like the address bar and tabs. You can enable kiosk mode when creating a browser by setting the `kiosk_mode` parameter to `true`.

Kiosk mode triggers a Chromium restart, which can take several seconds. Use [browser pools](https://www.kernel.sh/docs/browsers/pools/overview) to access kiosk mode browsers faster.

```
const browser = await kernel.browsers.create({
    kiosk_mode: true
});
```

## [​](#url-lifetime)URL lifetime

`browser_live_view_url` becomes invalid once the browser is [deleted](https://www.kernel.sh/docs/browsers/termination) manually or via timeout.

----
url: https://www.kernel.sh/docs/auth/faq
----

## How does automatic re-authentication work?

When you link credentials to a connection, Kernel monitors the login session and re-authenticates automatically when it expires. Periodic health checks detect logged-out sessions and trigger re-auth in the background, so the profile stays logged in without additional action on your part.

## How often are health checks performed?

Health checks on regular cadences based on your plan:

## How do I know if a Kernel can automatically re-authenticate a connection?

Check the `can_reauth` field on a connection. This boolean checks the following conditions:

1. **Credential linked** — A credential must be attached to the connection (stored in Kernel or via an external provider like [1Password](https://www.kernel.sh/docs/integrations/1password))
2. **No external action required** — The learned login flow doesn’t require human intervention

Only if all of the above conditions are met will `can_reauth` be `true`. When true, Kernel will attempt to automatically re-authenticate the connection.

### External actions that prevent auto-reauth

After a successful login, Kernel saves the login flow. If the flow includes steps that require human action—like SMS/email OTP, push notifications, or manual MFA selection—Kernel marks the connection as unable to auto-reauth because those steps can’t be automated without user input. If your login flow requires one of these, you can still automate around it:

## Which authentication methods are supported?

Managed Auth supports username/password authentication and most SSO providers.

## What happens if login fails?

If a login attempt fails, Kernel will retry with exponential backoff. After multiple failures, the [login flow](https://www.kernel.sh/docs/auth/hosted-ui) will be marked as failed and you’ll receive an error. Common failure reasons include:

## Can I use Managed Auth with any website?

Managed Auth works with most websites. Sites with aggressive bot detection may require additional configuration (stealth mode, proxies). Passkeys and hardware security keys are not currently supported.

## How is Managed Auth billed?

Managed Auth is included on all paid plans with no per-connection fees. It uses browser sessions to log in and keep your sessions fresh—these count toward your browser usage like any other browser session. Auth sessions are fast (typically 5-30 seconds each). Kernel monitors session health and re-authenticates automatically when sessions expire—most stay valid for days. For example, keeping 100 auth connections logged in typically costs less than $5/month in browser usage. See [Pricing & Limits](https://www.kernel.sh/docs/info/pricing#managed-auth) for details.

----
url: https://www.kernel.sh/docs/browsers/pools/scaling
----

## Introduction

This guide explains how to architect production-scale browser automation systems using Kernel, how to handle high-concurrency workloads, and best practices for building resilient systems. After understanding the [basics](https://www.kernel.sh/docs/browsers/create-a-browser) of our browsers, you should understand how to create and connect to individual browsers on-demand. This guide builds on that foundation to help you design systems using browser pools that can handle hundreds or thousands of concurrent browser tasks reliably.

## Understanding your requirements

Before selecting an architecture, assess your workload’s characteristics: **Concurrency**: How many browsers need to run simultaneously?

**Request Patterns**: How do tasks arrive?

**Throughput**: How quickly do you need to create and tear down browsers?

## Architecture patterns

### Direct browser creation (POC)

For proof-of-concept work and early production systems with modest concurrency needs, creating browsers on-demand is the simplest approach. **When to use:**

Example

### Single browser pool (scaling)

For production systems with consistent, high-frequency workloads, a browser pool allows you to access higher concurrency plus predictable performance. **When to use:**

Example

```
import Kernel from '@onkernel/sdk';
import { chromium } from 'playwright';

const kernel = new Kernel();
const POOL_NAME = 'production-pool';

// Initialize pool once (typically in deployment/startup)
async function initializePool() {
  await kernel.browserPools.create({
    name: POOL_NAME,
    size: 25, // Balance cost and availability
    timeout_seconds: 300, // Destroy browsers after 5 minutes of inactivity
    stealth: true,
    headless: false, // headless: true for cost savings if no live view needed
  });
}

async function processTask(taskData: any) {
  let session;
  
  try {
    // Acquire browser (returns immediately if available)
    session = await kernel.browserPools.acquire(POOL_NAME, {
      acquire_timeout_seconds: 30, // Wait up to 30s for availability
    });

    const browser = await chromium.connectOverCDP(session.cdp_ws_url);
    const context = browser.contexts()[0];
    const page = context.pages()[0];

    // Perform work
    await page.goto(taskData.url);
    // ... automation logic ...

    return { success: true, data: /* results */ };
  } catch (error) {
    console.error('Task failed:', error);
    return { success: false, error: error.message };
  } finally {
    // Critical: Always release back to pool
    if (session) {
      await kernel.browserPools.release(POOL_NAME, {
        session_id: session.session_id,
        reuse: true, // Reuse for efficiency
      });
    }
  }
}
```

**Key considerations:**

### Queue-based processing (high scale)

For systems exceeding pool capacity or with unpredictable bursts, implement a task queue to manage workloads gracefully. **When to use:**

Example

```
import { Queue } from 'bullmq'; // or any queue system
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();
const POOL_NAME = 'production-pool';
const POOL_SIZE = 50;

// Task queue configuration
const taskQueue = new Queue('browser-tasks', {
  connection: { /* Redis config */ }
});

// Worker that processes tasks
async function startWorker() {
  const worker = new Worker('browser-tasks', async (job) => {
    let session;
    
    try {
      // Acquire browser with reasonable timeout
      session = await kernel.browserPools.acquire(POOL_NAME, {
        acquire_timeout_seconds: 120,
      });

      const browser = await chromium.connectOverCDP(session.cdp_ws_url);
      const context = browser.contexts()[0];
      const page = context.pages()[0];

      // Process job data
      await page.goto(job.data.url);
      const result = await page.evaluate(() => /* extract data */);

      return { success: true, data: result };
    } catch (error) {
      // Handle errors with retry logic
      if (error.message.includes('timeout')) {
        throw new Error('RETRY'); // BullMQ will retry
      }
      throw error;
    } finally {
      if (session) {
        await kernel.browserPools.release(POOL_NAME, {
          session_id: session.session_id,
          reuse: true,
        });
      }
    }
  }, {
    connection: { /* Redis config */ },
    concurrency: POOL_SIZE, // Match pool size
  });

  return worker;
}

// Add tasks to queue
async function submitTask(taskData: any, priority?: number) {
  await taskQueue.add('process', taskData, {
    priority: priority || 5,
    attempts: 3,
    backoff: {
      type: 'exponential',
      delay: 2000,
    },
  });
}
```

**Queue-specific considerations:**

----
url: https://www.kernel.sh/docs/auth/credentials
----

Credentials allow you to store login information securely and enable Kernel’s automated re-authentication without requiring user interaction. **There are three ways to provide credentials:**

## Save credentials during login

By default, credentials entered during login are automatically saved for re-authentication. No extra parameters are needed:

Once saved, browser profiles stay authenticated automatically. When the session expires, Kernel re-authenticates using the stored credentials. Credentials are updated after every successful login. One-time codes (TOTP, SMS, etc.) are not saved. To opt out of credential saving, set `save_credentials: false` when creating the connection:

## Pre-store credentials

For fully automated flows where no user is involved, create credentials upfront:

Then link the credential when creating a connection:

### 2FA with TOTP

For sites with authenticator app 2FA, include `totp_secret` to fully automate login:

### SSO / OAuth

For sites with “Sign in with Google/GitHub/Microsoft”, set `sso_provider` and include the OAuth provider’s domains in `allowed_domains`. The workflow automatically clicks the matching SSO button and completes OAuth:

## Partial Credentials

Credentials don’t need to contain every field required by the login form. You can store what you have and collect the necessary fields from the user. `auth.connections.login()` pauses for missing values. As an example, the below credential has email + TOTP secret stored (and automatically handled), but no password. The password is dynamically collected from the user using Kernel’s Hosted UI or your Programmatic flow:

This is useful when you want to:

## Security

| Feature                | Description                                          |
| ---------------------- | ---------------------------------------------------- |
| **Encrypted at rest**  | Values encrypted using per-organization keys         |
| **Write-only**         | Values cannot be retrieved via API after creation    |
| **Never logged**       | Values are never written to logs                     |
| **Never shared**       | Values are never passed to LLMs                      |
| **Isolated execution** | Authentication runs in isolated browser environments |

## Notes

----
url: https://www.kernel.sh/docs/api-reference/browser-pools/get-browser-pool-details
----

```
{
  "id": "iv25ujqf37x3j07dwoffegqr",
  "available_count": 85,
  "acquired_count": 15,
  "created_at": "2023-11-07T05:31:56Z",
  "browser_pool_config": {
    "size": 10,
    "name": "my-pool",
    "fill_rate_per_minute": 10,
    "timeout_seconds": 600,
    "stealth": true,
    "headless": false,
    "profile": {
      "id": "<string>",
      "name": "<string>",
      "save_changes": false
    },
    "extensions": [
      {
        "id": "<string>",
        "name": "<string>"
      }
    ],
    "proxy_id": "<string>",
    "viewport": {
      "width": 1280,
      "height": 800,
      "refresh_rate": 60
    },
    "kiosk_mode": true
  },
  "name": "my-pool"
}
```

----
url: https://www.kernel.sh/docs/api-reference/extensions/upload-a-browser-extension
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.extensions.upload({ file: fs.createReadStream('path/to/file') });

console.log(response.id);
```

```
{
  "id": "<string>",
  "created_at": "2023-11-07T05:31:56Z",
  "size_bytes": 123,
  "name": "<string>",
  "last_used_at": "2023-11-07T05:31:56Z"
}
```

POST

/

extensions

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.extensions.upload({ file: fs.createReadStream('path/to/file') });

console.log(response.id);
```

```
{
  "id": "<string>",
  "created_at": "2023-11-07T05:31:56Z",
  "size_bytes": 123,
  "name": "<string>",
  "last_used_at": "2023-11-07T05:31:56Z"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Body

multipart/form-data

[​](#body-file)

file

file

required

ZIP file containing the browser extension.

[​](#body-name)

name

string

Optional unique name within the organization to reference this extension.

Pattern: `^[A-Za-z0-9._-]{1,255}$`

#### Response

Extension uploaded successfully

A browser extension uploaded to Kernel.

[​](#response-id)

id

string

required

Unique identifier for the extension

[​](#response-created-at)

created\_at

string\<date-time>

required

Timestamp when the extension was created

[​](#response-size-bytes)

size\_bytes

integer

required

Size of the extension archive in bytes

[​](#response-name-one-of-0)

name

string | null

Optional, easier-to-reference name for the extension. Must be unique within the organization.

[​](#response-last-used-at-one-of-0)

last\_used\_at

string\<date-time> | null

Timestamp when the extension was last used

[List browser extensions](https://www.kernel.sh/docs/api-reference/extensions/list-browser-extensions)

[Previous](https://www.kernel.sh/docs/api-reference/extensions/list-browser-extensions)

[Download extension archive](https://www.kernel.sh/docs/api-reference/extensions/download-extension-archive)

[Next](https://www.kernel.sh/docs/api-reference/extensions/download-extension-archive)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-processes/get-process-status
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.process.status('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', {
  id: 'id',
});

console.log(response.cpu_pct);
```

```
{
  "state": "running",
  "exit_code": 123,
  "cpu_pct": 123,
  "mem_bytes": 123
}
```

status

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.process.status('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', {
  id: 'id',
});

console.log(response.cpu_pct);
```

```
{
  "state": "running",
  "exit_code": 123,
  "cpu_pct": 123,
  "mem_bytes": 123
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

#### Response

Status

Current status of a process.

[​](#response-state)

state

enum\<string>

Process state.

Available options

:

`running`,

`exited`

[​](#response-exit-code-one-of-0)

exit\_code

integer | null

Exit code if the process has exited.

[​](#response-cpu-pct)

cpu\_pct

number

Estimated CPU usage percentage.

[​](#response-mem-bytes)

mem\_bytes

integer

Estimated resident memory usage in bytes.

[Execute a command asynchronously](https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-asynchronously)

[Previous](https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-asynchronously)

[Stream process stdout via SSE](https://www.kernel.sh/docs/api-reference/browser-processes/stream-process-stdout-via-sse)

[Next](https://www.kernel.sh/docs/api-reference/browser-processes/stream-process-stdout-via-sse)

Ctrl+I

----
url: https://www.kernel.sh/docs/integrations/computer-use/yutori
----

[n1](https://yutori.com/blog/introducing-n1) is Yutori’s pixels-to-actions LLM that predicts browser actions from screenshots. This computer use model enables AI agents to interact with web interfaces by analyzing visual content and generating appropriate mouse and keyboard actions. By integrating Yutori n1 with Kernel, you can run these AI-powered browser automations on cloud-hosted infrastructure, eliminating the need for local browser management and enabling scalable, reliable AI agents.

## [​](#quick-setup-with-our-yutori-example-app)Quick setup with our Yutori example app

Get started quickly with our Kernel app template that includes a pre-configured Yutori n1 integration:

```
kernel create --name my-yutori-app --template yutori
```

Choose `TypeScript` or `Python` as the programming language. Then follow the [Quickstart guide](https://www.kernel.sh/docs/quickstart) to deploy and run your Yutori automation on Kernel’s infrastructure.

## [​](#benefits-of-using-kernel-with-yutori-n1)Benefits of using Kernel with Yutori n1

* **No local browser management**: Run n1 automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel for concurrent AI agents
* **Stealth mode**: Built-in anti-detection features for reliable web interactions
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your Yutori agents with real-time browser viewing
* **Cloud infrastructure**: Run computationally intensive AI agents without local resource constraints

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Yutori app to Kernel
* Read the [Yutori n1 API documentation](https://docs.yutori.com/reference/n1) for model details

----
url: https://www.kernel.sh/docs/browsers/file-io
----

## Downloads

Kernel browsers run in fully sandboxed environments with writable filesystems. When your automation downloads a file, it’s saved inside the browser’s filesystem and can be retrieved using Kernel’s File I/O APIs.

### Playwright

Playwright performs downloads via the browser itself, so there are a few steps:

### Stagehand v3

When using Stagehand with Kernel browsers, you need to configure the download behavior in the `localBrowserLaunchOptions`:

Here’s a complete example:

```
import { Stagehand } from "@browserbasehq/stagehand";
import Kernel from "@onkernel/sdk";
import fs from "fs";

const DOWNLOAD_DIR = "/tmp/downloads";

// Poll listFiles until any file appears in the directory
async function waitForFile(
    kernel: Kernel,
    sessionId: string,
    dir: string,
    timeoutMs = 30_000
) {
    const start = Date.now();
    while (Date.now() - start < timeoutMs) {
        const files = await kernel.browsers.fs.listFiles(sessionId, { path: dir });
        if (files.length > 0) {
            return files[0];
        }
        await new Promise((r) => setTimeout(r, 500));
    }
    throw new Error(`No files found in ${dir} after ${timeoutMs}ms`);
}

async function main() {
    const kernel = new Kernel();

    console.log("Creating browser via Kernel...");
    const kernelBrowser = await kernel.browsers.create({
        stealth: true,
    });

    console.log(`Kernel Browser Session Started`);
    console.log(`Session ID: ${kernelBrowser.session_id}`);
    console.log(`Watch live: ${kernelBrowser.browser_live_view_url}`);

    // Initialize Stagehand with Kernel's CDP URL and download configuration
    const stagehand = new Stagehand({
        env: "LOCAL",
        verbose: 1,
        localBrowserLaunchOptions: {
            cdpUrl: kernelBrowser.cdp_ws_url,
            downloadsPath: DOWNLOAD_DIR,
            acceptDownloads: true,
        },
    });

    await stagehand.init();

    const page = stagehand.context.pages()[0];

    await page.goto("https://browser-tests-alpha.vercel.app/api/download-test");

    // Use Stagehand to click the download button
    await stagehand.act("Click the download file link");
    console.log("Download triggered");

    // Wait for the file to be fully available via Kernel's File I/O APIs
    console.log("Waiting for file to appear...");
    const downloadedFile = await waitForFile(
        kernel,
        kernelBrowser.session_id,
        DOWNLOAD_DIR
    );
    console.log(`File found: ${downloadedFile.name}`);

    const remotePath = `${DOWNLOAD_DIR}/${downloadedFile.name}`;
    console.log(`Reading file from: ${remotePath}`);

    // Read the file from Kernel browser's filesystem
    const resp = await kernel.browsers.fs.readFile(kernelBrowser.session_id, {
        path: remotePath,
    });

    // Save to local filesystem
    const bytes = await resp.bytes();
    fs.mkdirSync("downloads", { recursive: true });
    const localPath = `downloads/${downloadedFile.name}`;
    fs.writeFileSync(localPath, bytes);
    console.log(`Saved to ${localPath}`);

    // Clean up
    await stagehand.close();
    await kernel.browsers.deleteByID(kernelBrowser.session_id);
    console.log("Browser session closed");
}

main().catch((err) => {
    console.error(err);
    process.exit(1);
});
```

### Browser Use

Browser Use handles downloads automatically when configured properly.

## Uploads

Playwright’s `setInputFiles()` method allows you to upload files directly to file input elements. You can fetch a file from a URL and pass the buffer directly to `setInputFiles()`.

## Considerations

----
url: https://www.kernel.sh/docs/browsers/replays
----

Replays capture browser sessions as video recordings that you can view or download later. You have full control over when replays start and stop, allowing you to capture specific interactions or workflows.

## [​](#starting-and-stopping-recordings)Starting and stopping recordings

To start recording a browser session, use the replays API on an active browser:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();
const kernelBrowser = await kernel.browsers.create();

const replay = await kernel.browsers.replays.start(kernelBrowser.session_id);
console.log(`Recording started with ID: ${replay.replay_id}`);

// Perform some automation...

await kernel.browsers.replays.stop(replay.replay_id, { id: kernelBrowser.session_id });
console.log('Recording stopped and processing');
```

## [​](#multiple-recordings-per-session)Multiple recordings per session

You can create multiple replay recordings for a single browser session. Each recording gets a unique `replay_id` and can be started and stopped independently:

```
const replay1 = await kernel.browsers.replays.start(kernelBrowser.session_id);
// Perform some automation...
await kernel.browsers.replays.stop(replay1.replay_id, { id: kernelBrowser.session_id });

const replay2 = await kernel.browsers.replays.start(kernelBrowser.session_id);
// Perform different automation...
await kernel.browsers.replays.stop(replay2.replay_id, { id: kernelBrowser.session_id });
```

## [​](#downloading-all-replays)Downloading all replays

To access all replays for a browser session, list and access them via url or as downloads:

```
import fs from 'fs';
import { Buffer } from 'buffer';

const replays = await kernel.browsers.replays.list(kernelBrowser.session_id);

for (const replay of replays) {
  console.log(`Replay ID: ${replay.replay_id}`);
  console.log(`View URL: ${replay.replay_view_url}`);

  const videoData = await kernel.browsers.replays.download(
    replay.replay_id,
    { id: kernelBrowser.session_id }
  );

  const content = await videoData.blob();
  const buffer = Buffer.from(await content.arrayBuffer());

  const filename = `replay-${replay.replay_id}-${kernelBrowser.session_id}.mp4`;
  fs.writeFileSync(filename, buffer);
}
```

----
url: https://www.kernel.sh/docs/browsers/pools/faq
----

### When should I use browser pools vs. creating browsers on-demand?

Use browser pools when you need to run many browsers concurrently (50+ simultaneous browsers). Pools allow you to pre-configure a set of browsers for your use case, enabling you to scale to hundreds or thousands of concurrent browser sessions.

### How do I know if my pool is too small or too large?

Monitor the `available_count` metric. If it frequently drops to 0, your pool is too small. If it stays above 30-40% of the pool size during normal operation, you’re over-provisioned. Target 10-20% available browsers during typical load.

### What happens if I don’t release a browser back to the pool?

The browser will remain “acquired” until the idle timeout expires, at which point it’s destroyed and a new browser is created to refill the pool. Unreleased browsers create inefficiency and can exhaust your pool.

### What is `fill_rate_per_minute`?

`fill_rate_per_minute` is the percentage of the pool that will be refilled per minute. For example, if you set `fill_rate_per_minute` to 10, the pool will be refilled with 10% of the pool size per minute. When a browser from a pool is set to be destroyed (by reaching its specified `timeout_seconds` or `reuse: false`), a pool refill will be triggered to replace any destroyed browsers with new ones. Refill checks run once per minute.

### Can I update a pool’s configuration without recreating it?

Yes, use `kernel.browserPools.update()`. By default, idle browsers are discarded and rebuilt with new configuration. Set `discard_all_idle: false` to only apply changes to newly created browsers.

### Should I set `reuse: true` or `reuse: false` when releasing?

Use `reuse: true` (default) for efficiency. Only use `reuse: false` when you suspect browser state corruption or need a guaranteed clean browser session.

### How do pool timeouts interact with task duration?

The pool’s `timeout_seconds` only applies while the browser is acquired. If your task takes 5 minutes and timeout is 3 minutes, the browser won’t be destroyed—the timeout only triggers if the browser is idle (no CDP connection) for 3 minutes.

### Can I use different browser configurations within the same pool?

All browsers in a pool initialize with the same configuration. Calling `kernel.browserPools.update()` updates the configuration for all idle browsers in the pool. Once you’ve acquired a browser, you can apply certain [hot swap configurations](https://www.kernel.sh/docs/api-reference/browsers/update-browser-session) to that browser instance using `kernel.browsers.update()`.

### How do I handle rate limiting from target websites?

### What’s the best way to debug issues in production?

----
url: https://www.kernel.sh/docs/api-reference/browsers/ad-hoc-upload-one-or-more-unpacked-extensions-to-a-running-browser-instance
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.loadExtensions('id', {
  extensions: [{ name: 'name', zip_file: fs.createReadStream('path/to/file') }],
});
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

POST

/

browsers

/

{id}

/

extensions

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.loadExtensions('id', {
  extensions: [{ name: 'name', zip_file: fs.createReadStream('path/to/file') }],
});
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

multipart/form-data

[​](#body-extensions)

extensions

object\[]

required

List of extensions to upload and activate

Show child attributes

#### Response

Extensions uploaded, Chromium restarted, and DevTools is ready

[Update browser session](https://www.kernel.sh/docs/api-reference/browsers/update-browser-session)

[Previous](https://www.kernel.sh/docs/api-reference/browsers/update-browser-session)

[Execute a batch of computer actions sequentially](https://www.kernel.sh/docs/api-reference/browsers/execute-a-batch-of-computer-actions-sequentially)

[Next](https://www.kernel.sh/docs/api-reference/browsers/execute-a-batch-of-computer-actions-sequentially)

⌘I

----
url: https://www.kernel.sh/docs/auth/hosted-ui
----

Collect credentials securely via Kernel’s hosted page, then use the authenticated session in your automations. This is the recommended approach for most applications. Use the Hosted UI when:

* You need users to provide their credentials
* You want the simplest integration with minimal code
* You want Kernel to handle 2FA and multi-step login flows

## [​](#getting-started)Getting started

### [​](#1-create-a-connection)1. Create a Connection

A Managed Auth Connection associates a [profile](https://www.kernel.sh/docs/auth/profiles) to a domain you want to keep authenticated so you can use the auth connection future browsers.

```
const auth = await kernel.auth.connections.create({
  domain: 'linkedin.com',
  profile_name: 'linkedin-profile', // Name of the profile to associate with the connection
});
```

### [​](#2-start-a-login-session)2. Start a Login Session

Start a Managed Auth Session to get the hosted login URL.

```
const login = await kernel.auth.connections.login(auth.id);
```

### [​](#3-collect-credentials)3. Collect Credentials

Send the user to the hosted login page:

```
window.location.href = login.hosted_url;
```

The user will:

1. See the login page for the target website
2. Enter their credentials
3. Complete 2FA if needed

### [​](#4-poll-for-completion)4. Poll for Completion

On your backend, poll until authentication completes:

```
let state = await kernel.auth.connections.retrieve(auth.id);

while (state.flow_status === 'IN_PROGRESS') {
  await new Promise(r => setTimeout(r, 2000));
  state = await kernel.auth.connections.retrieve(auth.id);
}

if (state.status === 'AUTHENTICATED') {
  console.log('Authentication successful!');
}
```

Poll every 2 seconds. The session expires after 20 minutes if not completed, and the flow times out after 10 minutes of waiting for user input.

### [​](#5-use-the-profile)5. Use the Profile

Create browsers with the profile and navigate to the site. The browser session will already be authenticated:

```
const browser = await kernel.browsers.create({
  profile: { name: 'linkedin-profile' },
  stealth: true,
});

// Navigate to the site—you're already logged in
await page.goto('https://linkedin.com');
```

Managed Auth Connections are generated using Kernel’s [stealth](https://www.kernel.sh/docs/browsers/bot-detection/stealth) mode. Use `stealth: true` when creating authenticated browser sessions for the best experience.

## [​](#complete-example)Complete Example

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

// Create connection
const auth = await kernel.auth.connections.create({
  domain: 'doordash.com',
  profile_name: 'doordash-user-123',
});

// Start authentication
const login = await kernel.auth.connections.login(auth.id);

// Send user to hosted page
console.log('Login URL:', login.hosted_url);

// Poll for completion
let state = await kernel.auth.connections.retrieve(auth.id);
while (state.flow_status === 'IN_PROGRESS') {
  await new Promise(r => setTimeout(r, 2000));
  state = await kernel.auth.connections.retrieve(auth.id);
}

if (state.status === 'AUTHENTICATED') {
  const browser = await kernel.browsers.create({
    profile: { name: 'doordash-user-123' },
    stealth: true,
  });
  
  // Navigate to the site—you're already logged in
  await page.goto('https://doordash.com');
}
```

## [​](#adding-features)Adding Features

The basic flow above gets you started. Add these features as needed:

### [​](#credentials-and-auto-reauth)Credentials and Auto-Reauth

Credentials are saved after every successful login, enabling automatic re-authentication when the session expires. One-time codes (TOTP, SMS, etc.) are not saved. To opt out of credential saving, set `save_credentials: false` when creating the connection. See [Credentials](https://www.kernel.sh/docs/auth/credentials) for more on automated authentication.

### [​](#custom-login-url)Custom Login URL

If the site’s login page isn’t at the default location, specify it when creating the connection:

```
const auth = await kernel.auth.connections.create({
  domain: 'example.com',
  profile_name: 'my-profile',
  login_url: 'https://example.com/auth/signin',
});
```

### [​](#sso/oauth-support)SSO/OAuth Support

Sites with “Sign in with Google/GitHub/Microsoft” are supported. The user completes the OAuth flow with the provider, and the authenticated session is automatically saved to the Kernel profile. Make sure to add all of the OAuth provider’s domains to `allowed_domains`:

```
const auth = await kernel.auth.connections.create({
  domain: 'example.com',
  profile_name: 'my-profile',
  allowed_domains: ['accounts.google.com', 'google.com'],
});
```

### [​](#post-login-url)Post-Login URL

After successful authentication, `post_login_url` will be set to the page where the login landed. Use this start your automation from the right place:

```
const managedAuth = await kernel.auth.connections.retrieve(auth.id);

if (managedAuth.post_login_url) {
  await page.goto(managedAuth.post_login_url);
  // Start automation from the dashboard/home page
}
```

----
url: https://www.kernel.sh/docs/integrations/vercel/marketplace
----

## Integrate Kernel through the Vercel Marketplace

The Vercel Marketplace allows Vercel users to install and configure third-party services, like Kernel, directly from the Vercel dashboard. Kernel offers an [official integration](https://vercel.com/marketplace/kernel) that Vercel users can install to integrate Kernel cloud browsers into their Vercel projects. Kernel works out of the box with every major agent and automation framework, including **Browser Use**, **Stagehand**, **Playwright**, **Puppeteer**, or **Computer Use** via **OpenAI**, **Anthropic**, and **Gemini**.

### Installing the Kernel Integration

1. Navigate to the [Kernel integration](https://vercel.com/marketplace/kernel) in the Vercel Marketplace.
2. Click **Install** to add Kernel to your Vercel team.
3. Select your pricing plan.
4. Provide a name for your Kernel installation (this is not used for billing or anything else).
5. Click **Create**.

Vercel will automatically provision a Kernel User account, Organization, and API key for you. Vercel calls the provisioned account, Organization, and API key a **Resource**. Each Vercel team has an associated Kernel Organization. Kernel will automatically provision a new User account for you, or link to an existing Kernel User account if an account is found with the same email address. An equivalent role in Kernel is assigned to the user based on their Vercel team role. Roles and Vercel team membership are automatically synced to Kernel.

### Connecting to your Vercel projects

Once you’ve installed Kernel, you will need to connect it to one of your Vercel projects. Generally, a Kernel Organization should be connected to a single Vercel project. Connecting to a project will automatically sync your Kernel API key to your Vercel project’s environment variables. The following environment variable will be automatically synced to all environments:

### Configuring your Kernel integration

Most of your Kernel integration configuration will be done through the Kernel Dashboard. To access the Dashboard after installing the Kernel integration, navigate to your installation details page and click the **Open in Kernel** button.

### Using Kernel in your application

Once your Kernel API key is synced to your Vercel project, you can use it in your application. Here’s a quick example:

For more examples and features like profiles, stealth mode, and live view, check out the [Browsers documentation](https://www.kernel.sh/docs/browsers/create-a-browser).

### Pricing

The pricing for plans purchased through the Vercel Marketplace is the same as the pricing when purchased directly through Kernel. For more information on Kernel’s pricing and available plans, see the [Pricing page](https://onkernel.com/#pricing). Billing and usage data are reported hourly to Vercel and can be viewed directly in the Vercel Dashboard. Billing plan management can be done through both the Vercel Dashboard and the Kernel Dashboard.

### Limitations

The following limitations apply when using Kernel through the Vercel Marketplace:

----
url: https://www.kernel.sh/docs/api-reference/browser-computer-controls/press-one-or-more-keys-on-the-host-computer
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.pressKey('id', { keys: ['string'] });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

press\_key

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.pressKey('id', { keys: ['string'] });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-keys)

keys

string\[]

required

List of key symbols to press. Each item should be a key symbol supported by xdotool (see X11 keysym definitions). Examples include "Return", "Shift", "Ctrl", "Alt", "F5". Items in this list could also be combinations, e.g. "Ctrl+t" or "Ctrl+Shift+Tab".

[​](#body-duration)

duration

integer

default:0

Duration to hold the keys down in milliseconds. If omitted or 0, keys are tapped.

Required range

: `x >= 0`

[​](#body-hold-keys)

hold\_keys

string\[]

Optional modifier keys to hold during the key press sequence.

#### Response

Keys pressed successfully

[Type text on the browser instance](https://www.kernel.sh/docs/api-reference/browser-computer-controls/type-text-on-the-browser-instance)

[Previous](https://www.kernel.sh/docs/api-reference/browser-computer-controls/type-text-on-the-browser-instance)

[Scroll the mouse wheel at a position on the host computer](https://www.kernel.sh/docs/api-reference/browser-computer-controls/scroll-the-mouse-wheel-at-a-position-on-the-host-computer)

[Next](https://www.kernel.sh/docs/api-reference/browser-computer-controls/scroll-the-mouse-wheel-at-a-position-on-the-host-computer)

Ctrl+I

----
url: https://www.kernel.sh/docs/browsers/pools/overview
----

Browser pools let you maintain a set of reserved, identical browsers ready for immediate use. Use them to set your preferred browser configuration in advance, allowing you to minimize browser start-up latency and scale your workloads in production.

## Create a pool of reserved browsers

Create a browser pool with a specified size and configuration. All browsers in the pool share the same settings.

### Pool configuration options

Pools can be pre-configured with options like custom extensions, supported viewports, residential proxies, profiles, and more. See the [API reference](https://www.kernel.sh/docs/api-reference/browser-pools/create-a-browser-pool) for more details.

## Acquire a browser

Acquire a browser from the pool. The request returns immediately if a browser is available, or waits until one becomes available. The `acquire_timeout_seconds` parameter controls how long to wait; it defaults to the calculated time it would take to fill the pool at the pool’s configured [fill rate](https://www.kernel.sh/docs/api-reference/browser-pools/create-a-browser-pool#body-fill-rate-per-minute).

The acquired browser includes all the same properties as a regular browser session, including `cdp_ws_url` for CDP connections and `browser_live_view_url` for live viewing.

### Timeout behavior

Browsers remain in the pool indefinitely until acquired. Once acquired, the pool’s `timeout_seconds` applies just like a [regular browser timeout](https://www.kernel.sh/docs/browsers/termination#automatic-deletion-via-timeout)—if the browser is idle (no CDP or live view connection) for longer than the timeout, it is destroyed and **not** returned to the pool. The pool will automatically create a replacement browser at the pool’s configured [fill rate](https://www.kernel.sh/docs/api-reference/browser-pools/create-a-browser-pool#body-fill-rate-per-minute).

## Release a browser

When you’re done with a browser, release it back to the pool. By default, the browser instance is reused. Set `reuse: false` to destroy it and create a fresh one.

## Update a pool

Update the pool configuration. By default, all idle browsers are discarded and rebuilt with the new configuration.

By default, updating a pool discards all idle browsers and rebuilds them with the new configuration. Set `discard_all_idle: false` to keep existing idle browsers and only apply the new configuration to newly created browsers.

## Flush idle browsers

Destroy all idle browsers in the pool. Acquired browsers are not affected. The pool will automatically refill with the pool’s specified configuration.

## Get pool details

Retrieve the current status and configuration of a pool.

## List pools

List all browser pools in your organization.

## Delete a pool

Delete a browser pool and all browsers in it. By default, deletion is blocked if browsers are currently acquired. Use `force: true` to terminate acquired browsers and force deletion.

## Full example

This example assumes you’ve already created a pool named “my-pool”. In practice, you’d create pools once (via the SDK, CLI, or dashboard) and then acquire from them repeatedly.

## API reference

For more details on all available endpoints and parameters, see the [Browser Pools API reference](https://www.kernel.sh/docs/api-reference/browser-pools/list-browser-pools).

----
url: https://www.kernel.sh/docs/api-reference/browser-computer-controls/scroll-the-mouse-wheel-at-a-position-on-the-host-computer
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.scroll('id', { x: 0, y: 0 });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

scroll

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.scroll('id', { x: 0, y: 0 });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-x)

x

integer

required

X coordinate at which to perform the scroll

[​](#body-y)

y

integer

required

Y coordinate at which to perform the scroll

[​](#body-delta-x)

delta\_x

integer

default:0

Horizontal scroll amount in xdotool "wheel units." Positive scrolls right, negative scrolls left.

[​](#body-delta-y)

delta\_y

integer

default:0

Vertical scroll amount in xdotool "wheel units." Positive scrolls down, negative scrolls up.

[​](#body-hold-keys)

hold\_keys

string\[]

Modifier keys to hold during the scroll

#### Response

Scroll performed

[Press one or more keys on the host computer](https://www.kernel.sh/docs/api-reference/browser-computer-controls/press-one-or-more-keys-on-the-host-computer)

[Previous](https://www.kernel.sh/docs/api-reference/browser-computer-controls/press-one-or-more-keys-on-the-host-computer)

[Drag the mouse along a path](https://www.kernel.sh/docs/api-reference/browser-computer-controls/drag-the-mouse-along-a-path)

[Next](https://www.kernel.sh/docs/api-reference/browser-computer-controls/drag-the-mouse-along-a-path)

Ctrl+I

----
url: https://www.kernel.sh/docs/profiles/overview
----

[Skip to main content](https://www.kernel.sh/docs/profiles/overview#content-area)

##### Getting started

- [Introduction](https://www.kernel.sh/docs/introduction)
- [Quickstart](https://www.kernel.sh/docs/quickstart)

##### Working with your browser

- Basics

  - [Create a Browser](https://www.kernel.sh/docs/browsers/create-a-browser)
  - [Live View](https://www.kernel.sh/docs/browsers/live-view)
  - [Termination & Timeouts](https://www.kernel.sh/docs/browsers/termination)
  - [Standby Mode](https://www.kernel.sh/docs/browsers/standby)
  - [Headless Mode](https://www.kernel.sh/docs/browsers/headless)
- Intermediate

  - [Replays](https://www.kernel.sh/docs/browsers/replays)
  - [Viewports](https://www.kernel.sh/docs/browsers/viewport)
  - [GPU Acceleration](https://www.kernel.sh/docs/browsers/gpu-acceleration)
  - Auth

  - [File I/O](https://www.kernel.sh/docs/browsers/file-io)
  - [SSH Access](https://www.kernel.sh/docs/browsers/ssh)
  - [Computer Controls](https://www.kernel.sh/docs/browsers/computer-controls)
  - [Playwright Execution](https://www.kernel.sh/docs/browsers/playwright-execution)
- Advanced

  - Bot Anti-Detection

  - [Extensions](https://www.kernel.sh/docs/browsers/extensions)
  - Reserved Browsers

##### Building your app

- [Developing](https://www.kernel.sh/docs/apps/develop)
- [Deploying](https://www.kernel.sh/docs/apps/deploy)
- [Invoking](https://www.kernel.sh/docs/apps/invoke)
- [Stopping](https://www.kernel.sh/docs/apps/stop)
- [Secrets](https://www.kernel.sh/docs/apps/secrets)
- [Status](https://www.kernel.sh/docs/apps/status)
- [Logs](https://www.kernel.sh/docs/apps/logs)

##### Integrations

- [Overview](https://www.kernel.sh/docs/integrations/overview)
- [Agent Browser](https://www.kernel.sh/docs/integrations/agent-browser)
- [Browser Use](https://www.kernel.sh/docs/integrations/browser-use)
- [Claude Agent SDK](https://www.kernel.sh/docs/integrations/claude-agent-sdk)
- Computer Use

- [Laminar](https://www.kernel.sh/docs/integrations/laminar)
- [Magnitude](https://www.kernel.sh/docs/integrations/magnitude)
- [Notte](https://www.kernel.sh/docs/integrations/notte)
- [Vibium](https://www.kernel.sh/docs/integrations/vibium)
- [Stagehand](https://www.kernel.sh/docs/integrations/stagehand)
- [Val Town](https://www.kernel.sh/docs/integrations/valtown)
- Vercel

- [1Password](https://www.kernel.sh/docs/integrations/1password)

##### Migrations

- [Scrapybara](https://www.kernel.sh/docs/migrations/scrapybara)

##### Community

- [Github](https://github.com/onkernel/kernel-images)
- [Discord](https://discord.gg/FBrveQRcud)

##### Info

- [FAQ](https://www.kernel.sh/docs/browsers/faq)
- [Concepts](https://www.kernel.sh/docs/info/concepts)
- [Pricing & Limits](https://www.kernel.sh/docs/info/pricing)
- [Browsers on Unikernels](https://www.kernel.sh/docs/info/unikernels)

close

[Kernel home page![logo](https://mintcdn.com/tbd-6fc993ce/Lt3m2NlMiCztMtQK/logo/black.svg?fit=max&auto=format&n=Lt3m2NlMiCztMtQK&q=85&s=68e987c751954bbc1d35886a02636c73)](https://www.kernel.sh/docs)

Search...

Ctrl KAsk AI

Search...

Navigation

Page Not Found

[Guides](https://www.kernel.sh/docs/introduction) [API Reference](https://www.kernel.sh/docs/api-reference/invocations/list-invocations) [MCP](https://www.kernel.sh/docs/reference/mcp-server) [CLI](https://www.kernel.sh/docs/reference/cli) [Changelog](https://www.kernel.sh/changelog)

404

# Page Not Found

We couldn't find the page. Maybe you were looking for one of these pages below?

[Profiles](https://www.kernel.sh/docs/auth/profiles#profiles) [Download profile archive](https://www.kernel.sh/docs/api-reference/profiles/download-profile-archive) [Get profile by ID or name](https://www.kernel.sh/docs/api-reference/profiles/get-profile-by-id-or-name)

Ctrl+I

Assistant

Responses are generated using AI and may contain mistakes.

----
url: https://www.kernel.sh/docs/browsers/playwright-execution
----

Execute arbitrary Playwright/TypeScript code in a fresh execution context against your browser. The code runs in the same VM as the browser, minimizing latency and maximizing throughput. **For complex workloads, Kernel has a full [code execution platform](https://www.kernel.sh/docs/apps)**.

## [​](#how-it-works)How it works

When you execute Playwright code through this API:

* Your code runs directly in the browser’s VM (no CDP overhead)
* You have access to `page`, `context`, and `browser` variables
* You can `return` a value, which is returned in the response
* Execution is isolated in a fresh context each time

## [​](#quick-example)Quick example

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

// Create a browser
const kernelBrowser = await kernel.browsers.create();

// Execute Playwright code
const response = await kernel.browsers.playwright.execute(
  kernelBrowser.session_id,
  {
    code: `
      await page.goto('https://example.com');
      return await page.title();
    `
  }
);

console.log(response.result); // "Example Domain"
```

## [​](#available-variables)Available variables

Your code has access to these Playwright objects:

* `page` - The current page instance
* `context` - The browser context
* `browser` - The browser instance

## [​](#returning-values)Returning values

Use a `return` statement to send data back from your code:

```
const response = await kernel.browsers.playwright.execute(
  sessionId,
  {
    code: `
      await page.goto('https://example.com');
      const title = await page.title();
      const url = page.url();
      return { title, url };
    `
  }
);

console.log(response.result); // { title: "Example Domain", url: "https://example.com" }
```

## [​](#timeout-configuration)Timeout configuration

Set a custom timeout (default is 60 seconds, max is 300 seconds):

```
const response = await kernel.browsers.playwright.execute(
  sessionId,
  {
    code: `
      await page.goto('https://example.com');
      return await page.title();
    `,
    timeout_sec: 120
  }
);
```

## [​](#error-handling)Error handling

The response includes error information if execution fails:

```
const response = await kernel.browsers.playwright.execute(
  sessionId,
  {
    code: `
      await page.goto('https://invalid-url');
      return await page.title();
    `
  }
);

if (!response.success) {
  console.error('Error:', response.error);
  console.error('Stderr:', response.stderr);
}
```

## [​](#use-cases)Use cases

### [​](#web-scraping)Web scraping

Extract data from multiple pages without CDP overhead:

```
const response = await kernel.browsers.playwright.execute(
  sessionId,
  {
    code: `
      await page.goto('https://news.ycombinator.com');
      const titles = await page.$$eval('.titleline > a', 
        links => links.map(link => link.textContent)
      );
      return titles.slice(0, 10);
    `
  }
);
```

### [​](#form-automation)Form automation

Fill and submit forms quickly:

```
const response = await kernel.browsers.playwright.execute(
  sessionId,
  {
    code: `
      await page.goto('https://example.com/form');
      await page.fill('#email', 'user@example.com');
      await page.fill('#password', 'password123');
      await page.click('button[type="submit"]');
      await page.waitForNavigation();
      return page.url();
    `
  }
);
```

### [​](#testing-and-validation)Testing and validation

Run quick checks against your browser state:

```
const response = await kernel.browsers.playwright.execute(
  sessionId,
  {
    code: `
      const cookies = await context.cookies();
      const localStorage = await page.evaluate(() => 
        JSON.stringify(window.localStorage)
      );
      return { cookies, localStorage };
    `
  }
);
```

### [​](#screenshots)Screenshots

Capture screenshots using Playwright’s native screenshot API:

```
const response = await kernel.browsers.playwright.execute(
  sessionId,
  {
    code: `
      await page.goto('https://example.com');
      const screenshot = await page.screenshot({ 
        type: 'png',
        fullPage: true 
      });
      return screenshot.toString('base64');
    `
  }
);

// Decode and save the screenshot
const buffer = Buffer.from(response.result, 'base64');
fs.writeFileSync('screenshot.png', buffer);
```

For OS-level screenshots using coordinates and regions, see [Computer Controls](https://www.kernel.sh/docs/browsers/computer-controls#take-screenshots).

## [​](#performance-benefits)Performance benefits

Compared to connecting over CDP:

* **Lower latency** - Code runs in the same VM as the browser
* **Higher throughput** - No websocket overhead for commands
* **Simpler code** - No need to manage CDP connections

This makes it ideal for one-off operations where you need maximum speed.

## [​](#mcp-server-integration)MCP server integration

This feature is available as a tool in our [MCP server](https://www.kernel.sh/docs/reference/mcp-server). AI agents can use the `execute_playwright_code` tool to run Playwright code against browsers with automatic video replay and cleanup.

----
url: https://www.kernel.sh/docs/apps/stop
----

You can terminate an invocation that’s running. This is useful for stopping automations or agents stuck in an infinite loop.

Terminating an invocation also destroys any browsers associated with it.

## [​](#via-api)Via API

You can stop an invocation by setting its status to `failed`. This will cancel the invocation and mark it as terminated.

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const invocation = await kernel.invocations.update('invocation_id', {
  status: 'failed',
  output: JSON.stringify({ error: 'Invocation cancelled by user' }),
});
```

## [​](#via-cli)Via CLI

Use `ctrl-c` in the terminal tab where you launched the invocation.

----
url: https://www.kernel.sh/docs/browsers/headless
----

Kernel browsers ship in `Headful` mode by default. In Headful mode, the launched browser has a corresponding GUI. This enables features like [live view](https://www.kernel.sh/docs/browsers/live-view) and [replays](https://www.kernel.sh/docs/browsers/replays). `Headless` mode runs without a visual interface. They generally run faster and have a lighter footprint (1 GB rather than headful’s 8 GB), resulting in significant cost savings. This is useful for short-lived or highly concurrent browser automations. Some bot detectors may detect headless mode. To launch a Kernel browser in `Headless` mode, set its config:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create({
  headless: true,
});
```

[Live View](https://www.kernel.sh/docs/browsers/live-view) and [Replays](https://www.kernel.sh/docs/browsers/replays) are not available in headless mode.

----
url: https://www.kernel.sh/docs/api-reference/browser-replays/stop-a-browser-session-replay-recording
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.replays.stop('replay_id', { id: 'id' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

/

{replay\_id}

/

stop

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.replays.stop('replay_id', { id: 'id' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

[​](#parameter-replay-id)

replay\_id

string

required

Replay recording identifier

#### Response

Recording stopped successfully.

[Download a replay recording](https://www.kernel.sh/docs/api-reference/browser-replays/download-a-replay-recording)

[Previous](https://www.kernel.sh/docs/api-reference/browser-replays/download-a-replay-recording)

[Simulate a mouse click action on the browser instance](https://www.kernel.sh/docs/api-reference/browser-computer-controls/simulate-a-mouse-click-action-on-the-browser-instance)

[Next](https://www.kernel.sh/docs/api-reference/browser-computer-controls/simulate-a-mouse-click-action-on-the-browser-instance)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-pools/list-browser-pools
----

```
[
  {
    "id": "iv25ujqf37x3j07dwoffegqr",
    "available_count": 85,
    "acquired_count": 15,
    "created_at": "2023-11-07T05:31:56Z",
    "browser_pool_config": {
      "size": 10,
      "name": "my-pool",
      "fill_rate_per_minute": 10,
      "timeout_seconds": 600,
      "stealth": true,
      "headless": false,
      "profile": {
        "id": "<string>",
        "name": "<string>",
        "save_changes": false
      },
      "extensions": [
        {
          "id": "<string>",
          "name": "<string>"
        }
      ],
      "proxy_id": "<string>",
      "viewport": {
        "width": 1280,
        "height": 800,
        "refresh_rate": 60
      },
      "kiosk_mode": true
    },
    "name": "my-pool"
  }
]
```

----
url: https://www.kernel.sh/docs/api-reference/browser-logs/stream-log-files-on-the-browser-instance-via-sse
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const logEvent = await client.browsers.logs.stream('id', { source: 'path' });

console.log(logEvent.event);
```

```
{
  "event": "<string>",
  "timestamp": "2023-11-07T05:31:56Z",
  "message": "<string>"
}
```

GET

/

browsers

/

{id}

/

logs

/

stream

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const logEvent = await client.browsers.logs.stream('id', { source: 'path' });

console.log(logEvent.event);
```

```
{
  "event": "<string>",
  "timestamp": "2023-11-07T05:31:56Z",
  "message": "<string>"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Query Parameters

[​](#parameter-source)

source

enum\<string>

required

Available options

:

`path`,

`supervisor`

[​](#parameter-follow)

follow

boolean

default:true

[​](#parameter-path)

path

string

only required if source is path

[​](#parameter-supervisor-process)

supervisor\_process

string

only required if source is supervisor

#### Response

SSE stream of logs

A log entry from the application.

[​](#response-event)

event

string

required

Event type identifier (always "log").

Allowed value: `"log"`

[​](#response-timestamp)

timestamp

string\<date-time>

required

Time the log entry was produced.

[​](#response-message)

message

string

required

Log message text.

[Execute Playwright/TypeScript code against the browser](https://www.kernel.sh/docs/api-reference/browser-playwright/execute-playwrighttypescript-code-against-the-browser)

[Previous](https://www.kernel.sh/docs/api-reference/browser-playwright/execute-playwrighttypescript-code-against-the-browser)

[List browser pools](https://www.kernel.sh/docs/api-reference/browser-pools/list-browser-pools)

[Next](https://www.kernel.sh/docs/api-reference/browser-pools/list-browser-pools)

Ctrl+I

----
url: https://www.kernel.sh/docs/integrations/magnitude
----

[Magnitude](https://magnitude.run/) is an open source AI browser automation framework. It uses vision AI to enable you to control your browser with natural language. By integrating with Kernel, you can run Magnitude agents and automations with cloud-hosted browsers.

## [​](#adding-kernel-to-existing-magnitude-implementations)Adding Kernel to existing Magnitude implementations

If you already have a Magnitude implementation, you can easily switch to using Kernel’s cloud browsers by updating your browser configuration.

### [​](#1-install-the-kernel-sdk)1. Install the Kernel SDK

```
npm install @onkernel/sdk
```

### [​](#2-initialize-kernel-and-create-a-browser)2. Initialize Kernel and create a browser

Import the libraries and create a cloud browser session:

```
import { startBrowserAgent } from "magnitude-core";
import Kernel from '@onkernel/sdk';
import z from 'zod';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create({
  stealth: true,
});

console.log(`Live view url: ${kernelBrowser.browser_live_view_url}`);
```

### [​](#3-update-your-browser-configuration)3. Update your browser configuration

Replace your existing browser setup to use Kernel’s CDP URL and display settings:

```
const agent = await startBrowserAgent({
    url: 'https://magnitasks.com',
    narrate: true,
    browser: {
        cdp: kernelBrowser.cdp_ws_url,
    },
    llm: {
        provider: 'anthropic',
        options: {
            model: 'claude-sonnet-4-20250514'
        }
    }
});
```

### [​](#4-use-your-agent)4. Use your agent

Use Magnitude’s agent methods with the Kernel-powered browser:

```
await agent.act([
    'click on "Tasks" in the sidebar',
    'click on the first item in the "In Progress" column'
]);

const assignee = await agent.extract('Extract the task Assignee', z.string());

await agent.stop();

// Clean up the Kernel Browser Session
await kernel.browsers.deleteByID(kernelBrowser.session_id);
```

## [​](#quick-setup-with-our-magnitude-example-app)Quick setup with our Magnitude example app

Alternatively, you can use our Kernel app template that includes a pre-configured Magnitude integration:

```
kernel create --name my-magnitude-app --language typescript --template magnitude
```

Then follow the [Quickstart guide](https://www.kernel.sh/docs/quickstart) to deploy and run your Magnitude automation on Kernel’s infrastructure.

## [​](#benefits-of-using-kernel-with-magnitude)Benefits of using Kernel with Magnitude

* **No local browser management**: Run automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel
* **Stealth mode**: Built-in anti-detection features for web scraping
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your automations with real-time browser viewing

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Magnitude app to Kernel

----
url: https://www.kernel.sh/docs/reference/cli/mcp
----

## `kernel mcp install --target <target>`

Install Kernel MCP server configuration for a supported AI development tool. This command automatically configures the MCP server in your tool’s settings file.

| Flag                | Description                            |
| ------------------- | -------------------------------------- |
| `--target <target>` | Target AI tool to configure. Required. |

### Supported Targets

### Examples

### What It Does

The `mcp install` command:

1. **Locates the configuration file** for your target tool (e.g., `~/.cursor/mcp.json` for Cursor)
2. **Creates the file if it doesn’t exist** or reads the existing configuration
3. **Adds the Kernel MCP server** configuration with the correct settings for your tool
4. **Preserves existing MCP servers** - your other MCP configurations remain intact

### Configuration Details

The command automatically configures the appropriate transport and settings for each tool:

### Next Steps

After installation:

1. **Restart your tool** (or reload the window) to load the new MCP server
2. **Authenticate** when prompted - you’ll be redirected to authorize Kernel access via OAuth
3. **Start using Kernel tools** - browser automation capabilities will be available in your AI conversations

### Troubleshooting

If installation fails:

----
url: https://www.kernel.sh/docs/integrations/1password
----

Connect 1Password to automatically use credentials from your existing vaults with [Managed Auth](https://www.kernel.sh/docs/auth/overview). No need to manually create credentials in Kernel—1Password items are discovered by domain matching.

## How It Works

1. **Connect a service account** — Add your 1Password service account token in the dashboard
2. **Domain matching** — When Managed Auth needs credentials, it searches your connected vaults for items matching the target domain
3. **Automatic fill** — Credentials (including TOTP secrets) are used to complete authentication

## Setup

## Path Format

When using explicit paths, specify `VaultName/ItemName`:

## Domain Matching

1Password items are matched by their website/URL field:

| 1Password Item URL         | Matches Domain                       |
| -------------------------- | ------------------------------------ |
| `github.com`               | `github.com`                         |
| `https://github.com/login` | `github.com`                         |
| `*.example.com`            | `app.example.com`, `api.example.com` |

If multiple items match a domain, the first match is used. Organize your vaults to ensure the correct credentials are selected.

## TOTP Support

If your 1Password item has a one-time password (TOTP) field configured, it will be used automatically for 2FA—no additional setup needed.

## Credential Options

The `credential` object supports multiple sources:

| Type               | Example                                     | Description                       |
| ------------------ | ------------------------------------------- | --------------------------------- |
| Kernel credential  | `{ name: 'my-creds' }`                      | Use a credential stored in Kernel |
| 1Password explicit | `{ provider: 'my-1p', path: 'Vault/Item' }` | Use a specific 1Password item     |
| 1Password auto     | `{ provider: 'my-1p', auto: true }`         | Search 1Password by domain        |

If no `credential` is specified, the flow will wait for manual input.

## Security

| Feature                   | Description                                            |
| ------------------------- | ------------------------------------------------------ |
| **Token encrypted**       | Service account token encrypted with per-org keys      |
| **No credential storage** | Credentials stay in 1Password, retrieved at auth time  |
| **Vault access control**  | Limit access via 1Password service account permissions |
| **Audit trail**           | 1Password logs all credential access                   |

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/stream-filesystem-events-for-a-watch
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.fs.watch.events('watch_id', { id: 'id' });

console.log(response.path);
```

```
{
  "type": "CREATE",
  "path": "<string>",
  "name": "<string>",
  "is_dir": true
}
```

GET

/

events

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.fs.watch.events('watch_id', { id: 'id' });

console.log(response.path);
```

```
{
  "type": "CREATE",
  "path": "<string>",
  "name": "<string>",
  "is_dir": true
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

#### Response

SSE stream of filesystem events

Filesystem change event.

[​](#response-type)

type

enum\<string>

required

Event type.

Available options

:

`CREATE`,

`WRITE`,

`DELETE`,

`RENAME`

[​](#response-path)

path

string

required

Absolute path of the file or directory.

[​](#response-name)

name

string

Base name of the file or directory affected.

[​](#response-is-dir)

is\_dir

boolean

Whether the affected path is a directory.

[Watch a directory for changes](https://www.kernel.sh/docs/api-reference/browser-filesystem/watch-a-directory-for-changes)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/watch-a-directory-for-changes)

[Stop watching a directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/stop-watching-a-directory)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/stop-watching-a-directory)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-pools/release-a-browser-back-to-the-pool
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browserPools.release('id_or_name', { session_id: 'ts8iy3sg25ibheguyni2lg9t' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

POST

/

browser\_pools

/

{id\_or\_name}

/

release

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browserPools.release('id_or_name', { session_id: 'ts8iy3sg25ibheguyni2lg9t' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id-or-name)

id\_or\_name

string

required

Browser pool ID or name

#### Body

application/json

Request body for releasing a browser back to the pool.

[​](#body-session-id)

session\_id

string

required

Browser session ID to release back to the pool

Example:

`"ts8iy3sg25ibheguyni2lg9t"`

[​](#body-reuse)

reuse

boolean

default:true

Whether to reuse the browser instance or destroy it and create a new one. Defaults to true.

Example:

`false`

#### Response

Browser released successfully

[Acquire a browser from the pool](https://www.kernel.sh/docs/api-reference/browser-pools/acquire-a-browser-from-the-pool)

[Previous](https://www.kernel.sh/docs/api-reference/browser-pools/acquire-a-browser-from-the-pool)

[Flush all idle browsers in the pool](https://www.kernel.sh/docs/api-reference/browser-pools/flush-all-idle-browsers-in-the-pool)

[Next](https://www.kernel.sh/docs/api-reference/browser-pools/flush-all-idle-browsers-in-the-pool)

⌘I

----
url: https://www.kernel.sh/docs/browsers/gpu-acceleration
----

**Research Preview** — GPU acceleration is currently in research preview. Capacity may be limited and requires a Start-Up or Enterprise plan.

GPU acceleration enables GPU-accelerated rendering in Kernel browsers, providing enhanced performance for graphics-intensive workloads.

GPU acceleration is only available for headful browsers.

## [​](#enable-gpu-acceleration)Enable GPU acceleration

Set the `gpu` parameter to `true` when creating a browser:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create({
  gpu: true
});
```

You can also enable GPU acceleration in the dashboard when deploying a browser under **Advanced Configuration**.

## [​](#use-cases)Use cases

GPU acceleration is useful for:

* High performance live view streaming
* Rendering complex 3D graphics or WebGL content
* Video processing and playback
* Canvas-heavy applications

## [​](#availability)Availability

GPU acceleration is available on Start-Up and Enterprise plans. Due to limited capacity during the research preview, GPU-enabled browsers may not always be available.

----
url: https://www.kernel.sh/docs/api-reference/browser-replays/list-browser-session-replays
----

[Skip to main content](#content-area)

[Kernel home page](/docs)

[Guides](/docs/introduction)[API Reference](/docs/api-reference/invocations/list-invocations)[MCP](/docs/reference/mcp-server)[CLI](/docs/reference/cli)[Changelog](https://www.kernel.sh/changelog)



##### Invocations

* [GET](/docs/api-reference/invocations/list-invocations)

  [List invocations](/docs/api-reference/invocations/list-invocations)
* [POST](/docs/api-reference/invocations/invoke-an-action)

  [Invoke an action](/docs/api-reference/invocations/invoke-an-action)
* [GET](/docs/api-reference/invocations/get-invocation-details)

  [Get invocation details](/docs/api-reference/invocations/get-invocation-details)
* [PATCH](/docs/api-reference/invocations/update-invocation)

  [Update invocation](/docs/api-reference/invocations/update-invocation)
* [GET](/docs/api-reference/invocations/list-browsers-for-an-invocation)

  [List browsers for an invocation](/docs/api-reference/invocations/list-browsers-for-an-invocation)
* [DEL](/docs/api-reference/invocations/delete-browser-sessions-for-an-invocation)

  [Delete browser sessions for an invocation](/docs/api-reference/invocations/delete-browser-sessions-for-an-invocation)
* [GET](/docs/api-reference/invocations/stream-invocation-events-via-sse)

  [Stream invocation events via SSE](/docs/api-reference/invocations/stream-invocation-events-via-sse)

##### Proxies

* [GET](/docs/api-reference/proxies/list-proxies)

  [List proxies](/docs/api-reference/proxies/list-proxies)
* [POST](/docs/api-reference/proxies/create-a-proxy)

  [Create a proxy](/docs/api-reference/proxies/create-a-proxy)
* [GET](/docs/api-reference/proxies/get-proxy-by-id)

  [Get proxy by ID](/docs/api-reference/proxies/get-proxy-by-id)
* [DEL](/docs/api-reference/proxies/delete-proxy-by-id)

  [Delete proxy by ID](/docs/api-reference/proxies/delete-proxy-by-id)
* [POST](/docs/api-reference/proxies/check-proxy-health)

  [Check proxy health](/docs/api-reference/proxies/check-proxy-health)

##### Browsers

* [GET](/docs/api-reference/browsers/list-browser-sessions)

  [List browser sessions](/docs/api-reference/browsers/list-browser-sessions)
* [POST](/docs/api-reference/browsers/create-a-browser-session)

  [Create a browser session](/docs/api-reference/browsers/create-a-browser-session)
* [DEL](/docs/api-reference/browsers/delete-a-persistent-browser-session)

  [Delete a persistent browser session](/docs/api-reference/browsers/delete-a-persistent-browser-session)

  [deprecated](/docs/api-reference/browsers/delete-a-persistent-browser-session)
* [GET](/docs/api-reference/browsers/get-browser-session-details)

  [Get browser session details](/docs/api-reference/browsers/get-browser-session-details)
* [DEL](/docs/api-reference/browsers/delete-a-browser-session-by-id)

  [Delete a browser session by ID.](/docs/api-reference/browsers/delete-a-browser-session-by-id)
* [PATCH](/docs/api-reference/browsers/update-browser-session)

  [Update browser session](/docs/api-reference/browsers/update-browser-session)
* [POST](/docs/api-reference/browsers/ad-hoc-upload-one-or-more-unpacked-extensions-to-a-running-browser-instance)

  [Ad-hoc upload one or more unpacked extensions to a running browser instance.](/docs/api-reference/browsers/ad-hoc-upload-one-or-more-unpacked-extensions-to-a-running-browser-instance)
* [POST](/docs/api-reference/browsers/execute-a-batch-of-computer-actions-sequentially)

  [Execute a batch of computer actions sequentially](/docs/api-reference/browsers/execute-a-batch-of-computer-actions-sequentially)
* [POST](/docs/api-reference/browsers/get-the-current-mouse-cursor-position-on-the-browser-instance)

  [Get the current mouse cursor position on the browser instance](/docs/api-reference/browsers/get-the-current-mouse-cursor-position-on-the-browser-instance)

##### Browser Replays

* [GET](/docs/api-reference/browser-replays/list-browser-session-replays)

  [List browser session replays](/docs/api-reference/browser-replays/list-browser-session-replays)
* [POST](/docs/api-reference/browser-replays/start-a-browser-session-replay-recording)

  [Start a browser session replay recording](/docs/api-reference/browser-replays/start-a-browser-session-replay-recording)
* [GET](/docs/api-reference/browser-replays/download-a-replay-recording)

  [Download a replay recording](/docs/api-reference/browser-replays/download-a-replay-recording)
* [POST](/docs/api-reference/browser-replays/stop-a-browser-session-replay-recording)

  [Stop a browser session replay recording](/docs/api-reference/browser-replays/stop-a-browser-session-replay-recording)

##### Browser Computer Controls

* [POST](/docs/api-reference/browser-computer-controls/simulate-a-mouse-click-action-on-the-browser-instance)

  [Simulate a mouse click action on the browser instance](/docs/api-reference/browser-computer-controls/simulate-a-mouse-click-action-on-the-browser-instance)
* [POST](/docs/api-reference/browser-computer-controls/move-the-mouse-cursor-to-the-specified-coordinates-on-the-browser-instance)

  [Move the mouse cursor to the specified coordinates on the browser instance](/docs/api-reference/browser-computer-controls/move-the-mouse-cursor-to-the-specified-coordinates-on-the-browser-instance)
* [POST](/docs/api-reference/browser-computer-controls/capture-a-screenshot-of-the-browser-instance)

  [Capture a screenshot of the browser instance](/docs/api-reference/browser-computer-controls/capture-a-screenshot-of-the-browser-instance)
* [POST](/docs/api-reference/browser-computer-controls/type-text-on-the-browser-instance)

  [Type text on the browser instance](/docs/api-reference/browser-computer-controls/type-text-on-the-browser-instance)
* [POST](/docs/api-reference/browser-computer-controls/press-one-or-more-keys-on-the-host-computer)

  [Press one or more keys on the host computer](/docs/api-reference/browser-computer-controls/press-one-or-more-keys-on-the-host-computer)
* [POST](/docs/api-reference/browser-computer-controls/scroll-the-mouse-wheel-at-a-position-on-the-host-computer)

  [Scroll the mouse wheel at a position on the host computer](/docs/api-reference/browser-computer-controls/scroll-the-mouse-wheel-at-a-position-on-the-host-computer)
* [POST](/docs/api-reference/browser-computer-controls/drag-the-mouse-along-a-path)

  [Drag the mouse along a path](/docs/api-reference/browser-computer-controls/drag-the-mouse-along-a-path)
* [POST](/docs/api-reference/browser-computer-controls/set-cursor-visibility)

  [Set cursor visibility](/docs/api-reference/browser-computer-controls/set-cursor-visibility)
* [POST](/docs/api-reference/browser-computer-controls/read-text-from-the-clipboard-on-the-browser-instance)

  [Read text from the clipboard on the browser instance](/docs/api-reference/browser-computer-controls/read-text-from-the-clipboard-on-the-browser-instance)
* [POST](/docs/api-reference/browser-computer-controls/write-text-to-the-clipboard-on-the-browser-instance)

  [Write text to the clipboard on the browser instance](/docs/api-reference/browser-computer-controls/write-text-to-the-clipboard-on-the-browser-instance)

##### Apps

* [GET](/docs/api-reference/apps/list-apps)

  [List apps](/docs/api-reference/apps/list-apps)

##### Deployments

* [GET](/docs/api-reference/deployments/list-deployments)

  [List deployments](/docs/api-reference/deployments/list-deployments)
* [POST](/docs/api-reference/deployments/create-a-deployment)

  [Create a deployment](/docs/api-reference/deployments/create-a-deployment)
* [GET](/docs/api-reference/deployments/get-deployment-details)

  [Get deployment details](/docs/api-reference/deployments/get-deployment-details)
* [DEL](/docs/api-reference/deployments/delete-a-deployment)

  [Delete a deployment](/docs/api-reference/deployments/delete-a-deployment)
* [GET](/docs/api-reference/deployments/stream-deployment-events-via-sse)

  [Stream deployment events via SSE](/docs/api-reference/deployments/stream-deployment-events-via-sse)

##### Browser Filesystem

* [GET](/docs/api-reference/browser-filesystem/read-file-contents)

  [Read file contents](/docs/api-reference/browser-filesystem/read-file-contents)
* [PUT](/docs/api-reference/browser-filesystem/write-or-create-a-file)

  [Write or create a file](/docs/api-reference/browser-filesystem/write-or-create-a-file)
* [GET](/docs/api-reference/browser-filesystem/list-files-in-a-directory)

  [List files in a directory](/docs/api-reference/browser-filesystem/list-files-in-a-directory)
* [PUT](/docs/api-reference/browser-filesystem/create-a-new-directory)

  [Create a new directory](/docs/api-reference/browser-filesystem/create-a-new-directory)
* [PUT](/docs/api-reference/browser-filesystem/delete-a-file)

  [Delete a file](/docs/api-reference/browser-filesystem/delete-a-file)
* [PUT](/docs/api-reference/browser-filesystem/delete-a-directory)

  [Delete a directory](/docs/api-reference/browser-filesystem/delete-a-directory)
* [PUT](/docs/api-reference/browser-filesystem/set-file-or-directory-permissionsownership)

  [Set file or directory permissions/ownership](/docs/api-reference/browser-filesystem/set-file-or-directory-permissionsownership)
* [GET](/docs/api-reference/browser-filesystem/get-information-about-a-file-or-directory)

  [Get information about a file or directory](/docs/api-reference/browser-filesystem/get-information-about-a-file-or-directory)
* [PUT](/docs/api-reference/browser-filesystem/move-or-rename-a-file-or-directory)

  [Move or rename a file or directory](/docs/api-reference/browser-filesystem/move-or-rename-a-file-or-directory)
* [POST](/docs/api-reference/browser-filesystem/watch-a-directory-for-changes)

  [Watch a directory for changes](/docs/api-reference/browser-filesystem/watch-a-directory-for-changes)
* [GET](/docs/api-reference/browser-filesystem/stream-filesystem-events-for-a-watch)

  [Stream filesystem events for a watch](/docs/api-reference/browser-filesystem/stream-filesystem-events-for-a-watch)
* [DEL](/docs/api-reference/browser-filesystem/stop-watching-a-directory)

  [Stop watching a directory](/docs/api-reference/browser-filesystem/stop-watching-a-directory)
* [GET](/docs/api-reference/browser-filesystem/download-a-directory-as-a-zip-archive)

  [Download a directory as a ZIP archive](/docs/api-reference/browser-filesystem/download-a-directory-as-a-zip-archive)
* [POST](/docs/api-reference/browser-filesystem/upload-one-or-more-files)

  [Upload one or more files](/docs/api-reference/browser-filesystem/upload-one-or-more-files)
* [POST](/docs/api-reference/browser-filesystem/upload-a-zip-archive-and-extract-it)

  [Upload a zip archive and extract it](/docs/api-reference/browser-filesystem/upload-a-zip-archive-and-extract-it)

##### Browser Processes

* [POST](/docs/api-reference/browser-processes/execute-a-command-synchronously)

  [Execute a command synchronously](/docs/api-reference/browser-processes/execute-a-command-synchronously)
* [POST](/docs/api-reference/browser-processes/execute-a-command-asynchronously)

  [Execute a command asynchronously](/docs/api-reference/browser-processes/execute-a-command-asynchronously)
* [GET](/docs/api-reference/browser-processes/get-process-status)

  [Get process status](/docs/api-reference/browser-processes/get-process-status)
* [GET](/docs/api-reference/browser-processes/stream-process-stdout-via-sse)

  [Stream process stdout via SSE](/docs/api-reference/browser-processes/stream-process-stdout-via-sse)
* [POST](/docs/api-reference/browser-processes/write-to-process-stdin)

  [Write to process stdin](/docs/api-reference/browser-processes/write-to-process-stdin)
* [POST](/docs/api-reference/browser-processes/send-signal-to-process)

  [Send signal to process](/docs/api-reference/browser-processes/send-signal-to-process)
* [POST](/docs/api-reference/browser-processes/resize-a-pty-backed-process-terminal)

  [Resize a PTY-backed process terminal](/docs/api-reference/browser-processes/resize-a-pty-backed-process-terminal)

##### Browser Playwright

* [POST](/docs/api-reference/browser-playwright/execute-playwrighttypescript-code-against-the-browser)

  [Execute Playwright/TypeScript code against the browser](/docs/api-reference/browser-playwright/execute-playwrighttypescript-code-against-the-browser)

##### Browser Logs

* [GET](/docs/api-reference/browser-logs/stream-log-files-on-the-browser-instance-via-sse)

  [Stream log files on the browser instance via SSE](/docs/api-reference/browser-logs/stream-log-files-on-the-browser-instance-via-sse)

##### Browser Pools

* [GET](/docs/api-reference/browser-pools/list-browser-pools)

  [List browser pools](/docs/api-reference/browser-pools/list-browser-pools)
* [POST](/docs/api-reference/browser-pools/create-a-browser-pool)

  [Create a browser pool](/docs/api-reference/browser-pools/create-a-browser-pool)
* [GET](/docs/api-reference/browser-pools/get-browser-pool-details)

  [Get browser pool details](/docs/api-reference/browser-pools/get-browser-pool-details)
* [DEL](/docs/api-reference/browser-pools/delete-a-browser-pool)

  [Delete a browser pool](/docs/api-reference/browser-pools/delete-a-browser-pool)
* [PATCH](/docs/api-reference/browser-pools/update-a-browser-pool)

  [Update a browser pool](/docs/api-reference/browser-pools/update-a-browser-pool)
* [POST](/docs/api-reference/browser-pools/acquire-a-browser-from-the-pool)

  [Acquire a browser from the pool](/docs/api-reference/browser-pools/acquire-a-browser-from-the-pool)
* [POST](/docs/api-reference/browser-pools/release-a-browser-back-to-the-pool)

  [Release a browser back to the pool](/docs/api-reference/browser-pools/release-a-browser-back-to-the-pool)
* [POST](/docs/api-reference/browser-pools/flush-all-idle-browsers-in-the-pool)

  [Flush all idle browsers in the pool](/docs/api-reference/browser-pools/flush-all-idle-browsers-in-the-pool)

##### Profiles

* [GET](/docs/api-reference/profiles/list-profiles)

  [List profiles](/docs/api-reference/profiles/list-profiles)
* [POST](/docs/api-reference/profiles/create-a-new-profile)

  [Create a new profile](/docs/api-reference/profiles/create-a-new-profile)
* [GET](/docs/api-reference/profiles/get-profile-by-id-or-name)

  [Get profile by ID or name](/docs/api-reference/profiles/get-profile-by-id-or-name)
* [DEL](/docs/api-reference/profiles/delete-profile-by-id-or-name)

  [Delete profile by ID or name](/docs/api-reference/profiles/delete-profile-by-id-or-name)
* [GET](/docs/api-reference/profiles/download-profile-archive)

  [Download profile archive](/docs/api-reference/profiles/download-profile-archive)

##### Managed Auth

* [GET](/docs/api-reference/managed-auth/list-auth-connections)

  [List auth connections](/docs/api-reference/managed-auth/list-auth-connections)
* [POST](/docs/api-reference/managed-auth/create-auth-connection)

  [Create auth connection](/docs/api-reference/managed-auth/create-auth-connection)
* [GET](/docs/api-reference/managed-auth/get-auth-connection)

  [Get auth connection](/docs/api-reference/managed-auth/get-auth-connection)
* [DEL](/docs/api-reference/managed-auth/delete-auth-connection)

  [Delete auth connection](/docs/api-reference/managed-auth/delete-auth-connection)
* [POST](/docs/api-reference/managed-auth/start-login-flow)

  [Start login flow](/docs/api-reference/managed-auth/start-login-flow)
* [POST](/docs/api-reference/managed-auth/submit-field-values)

  [Submit field values](/docs/api-reference/managed-auth/submit-field-values)
* [GET](/docs/api-reference/managed-auth/stream-login-flow-events-via-sse)

  [Stream login flow events via SSE](/docs/api-reference/managed-auth/stream-login-flow-events-via-sse)

##### Extensions

* [GET](/docs/api-reference/extensions/list-browser-extensions)

  [List browser extensions](/docs/api-reference/extensions/list-browser-extensions)
* [POST](/docs/api-reference/extensions/upload-a-browser-extension)

  [Upload a browser extension](/docs/api-reference/extensions/upload-a-browser-extension)
* [GET](/docs/api-reference/extensions/download-extension-archive)

  [Download extension archive](/docs/api-reference/extensions/download-extension-archive)
* [DEL](/docs/api-reference/extensions/delete-extension-by-id-or-name)

  [Delete extension by ID or name](/docs/api-reference/extensions/delete-extension-by-id-or-name)
* [GET](/docs/api-reference/extensions/download-unpacked-extension-from-chrome-web-store)

  [Download unpacked extension from Chrome Web Store](/docs/api-reference/extensions/download-unpacked-extension-from-chrome-web-store)

JavaScript

Copy

Ask AI

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const replays = await client.browsers.replays.list('id');

console.log(replays);
```

Copy

Ask AI

```
[
  {
    "replay_id": "<string>",
    "started_at": "2023-11-07T05:31:56Z",
    "finished_at": "2023-11-07T05:31:56Z",
    "replay_view_url": "https://api.onkernel.com/browser/replays?jwt=eyJ0eXAi...&replay_id=7e2c1a9f-1234-4cde-9abc-ffeedd001122"
  }
]
```

GET

Copy

Ask AI

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const replays = await client.browsers.replays.list('id');

console.log(replays);
```

Copy

Ask AI

```
[
  {
    "replay_id": "<string>",
    "started_at": "2023-11-07T05:31:56Z",
    "finished_at": "2023-11-07T05:31:56Z",
    "replay_view_url": "https://api.onkernel.com/browser/replays?jwt=eyJ0eXAi...&replay_id=7e2c1a9f-1234-4cde-9abc-ffeedd001122"
  }
]
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Response

List of replays retrieved successfully.

[​](#response-items-replay-id)

replay\_id

string

required

Unique identifier for the replay recording.

[​](#response-items-started-at-one-of-0)

started\_at

string\<date-time> | null

Timestamp when replay started

[​](#response-items-finished-at-one-of-0)

finished\_at

string\<date-time> | null

Timestamp when replay finished

[​](#response-items-replay-view-url)

replay\_view\_url

string

URL for viewing the replay recording.

Example:

`"https://api.onkernel.com/browser/replays?jwt=eyJ0eXAi...&replay_id=7e2c1a9f-1234-4cde-9abc-ffeedd001122"`

[Get the current mouse cursor position on the browser instance](/docs/api-reference/browsers/get-the-current-mouse-cursor-position-on-the-browser-instance)

[Previous](/docs/api-reference/browsers/get-the-current-mouse-cursor-position-on-the-browser-instance)

[Start a browser session replay recording](/docs/api-reference/browser-replays/start-a-browser-session-replay-recording)

[Next](/docs/api-reference/browser-replays/start-a-browser-session-replay-recording)

⌘I

Assistant

Responses are generated using AI and may contain mistakes.

----
url: https://www.kernel.sh/docs/api-reference/browser-computer-controls/drag-the-mouse-along-a-path
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.dragMouse('id', {
  path: [
    [0, 0],
    [0, 0],
  ],
});
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

drag\_mouse

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.dragMouse('id', {
  path: [
    [0, 0],
    [0, 0],
  ],
});
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-path)

path

integer\[]\[]

required

Ordered list of \[x, y] coordinate pairs to move through while dragging. Must contain at least 2 points.

Minimum array length: `2`

Required array length: `2` element

s

[​](#body-button)

button

enum\<string>

Mouse button to drag with

Available options

:

`left`,

`middle`,

`right`

[​](#body-delay)

delay

integer

default:0

Delay in milliseconds between button down and starting to move along the path.

Required range

: `x >= 0`

[​](#body-steps-per-segment)

steps\_per\_segment

integer

default:10

Number of relative move steps per segment in the path. Minimum 1.

Required range

: `x >= 1`

[​](#body-step-delay-ms)

step\_delay\_ms

integer

default:50

Delay in milliseconds between relative steps while dragging (not the initial delay).

Required range

: `x >= 0`

[​](#body-hold-keys)

hold\_keys

string\[]

Modifier keys to hold during the drag

[​](#body-smooth)

smooth

boolean

default:true

Use human-like Bezier curves between path waypoints instead of linear interpolation. When true, steps\_per\_segment and step\_delay\_ms are ignored.

[​](#body-duration-ms)

duration\_ms

integer

Target total duration in milliseconds for the entire drag movement when smooth=true. Omit for automatic timing based on total path length.

Required range

: `50 <= x <= 10000`

#### Response

Drag performed

[Scroll the mouse wheel at a position on the host computer](https://www.kernel.sh/docs/api-reference/browser-computer-controls/scroll-the-mouse-wheel-at-a-position-on-the-host-computer)

[Previous](https://www.kernel.sh/docs/api-reference/browser-computer-controls/scroll-the-mouse-wheel-at-a-position-on-the-host-computer)

[Set cursor visibility](https://www.kernel.sh/docs/api-reference/browser-computer-controls/set-cursor-visibility)

[Next](https://www.kernel.sh/docs/api-reference/browser-computer-controls/set-cursor-visibility)

Ctrl+I

----
url: https://www.kernel.sh/docs/proxies/custom
----

Custom proxies allow you to use your own proxy servers with Kernel browsers. This is useful when you have existing proxy infrastructure or specific proxy requirements not covered by Kernel’s managed options.

## Configuration

Specify the host, port, and optional authentication credentials for your proxy server:

## Configuration Parameters

## Bypass hosts

Configure specific hostnames to bypass your custom proxy:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const proxy = await kernel.proxies.create({
  type: 'custom',
  name: 'custom-with-bypass',
  protocol: 'https',
  config: {
    host: 'proxy.example.com',
    port: 443,
    username: 'user123',
    password: 'secure_password',
  },
  bypass_hosts: [
    'localhost',
    'internal.service.local',
    '*.trusted-domain.com',
  ],
});
```

This is useful for accessing internal services or metadata endpoints without routing through your proxy. See the [overview](https://www.kernel.sh/docs/proxies/overview#bypass-hosts) for full bypass host rules.

----
url: https://www.kernel.sh/docs/integrations/computer-use/anthropic
----

[Computer Use](https://docs.claude.com/en/docs/agents-and-tools/tool-use/computer-use-tool) is Anthropic’s groundbreaking capability that enables Claude to interact with computers the way humans do by looking at screens, moving cursors, clicking buttons, and typing text. This powerful feature allows AI agents to control web browsers, navigate interfaces, and perform complex tasks across applications. By integrating Computer Use with Kernel, you can run these AI-powered browser automations on cloud-hosted infrastructure, eliminating the need for local browser management and enabling scalable, reliable AI agents.

## [​](#quick-setup-with-computer-use)Quick setup with Computer Use

Get started with Computer Use and Kernel using our pre-configured app template:

```
kernel create --name my-computer-use-app --template computer-use
```

Choose `TypeScript` or `Python` as the programming language. Then follow the [Quickstart guide](https://www.kernel.sh/docs/quickstart) to deploy and run your Computer Use automation on Kernel’s infrastructure.

## [​](#benefits-of-using-kernel-with-computer-use)Benefits of using Kernel with Computer Use

* **No local browser management**: Run Computer Use automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel for concurrent AI agents
* **Stealth mode**: Built-in anti-detection features for reliable web interactions
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your Computer Use agents with real-time browser viewing
* **Cloud infrastructure**: Run computationally intensive AI agents without local resource constraints

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your Computer Use automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Computer Use app to Kernel

----
url: https://www.kernel.sh/docs/reference/cli/apps
----

## `kernel deploy <file>`

Deploy an app to Kernel from the current directory. The entrypoint file and dependency manifest must live in the project root.

| Flag                       | Description                                                        |
| -------------------------- | ------------------------------------------------------------------ |
| `--version <version>`      | Use a specific version label (default: latest).                    |
| `--force`                  | Overwrite an existing version with the same label.                 |
| `--env <KEY=VALUE>`, `-e`  | Set environment variables (repeatable).                            |
| `--env-file <file>`        | Load environment variables from a file (repeatable).               |
| `--output json`, `-o json` | Output JSONL (one JSON object per line for each deployment event). |

## `kernel deploy logs <deployment_id>`

Stream build and runtime logs for a deployment.

| Flag                       | Description                                                                                                |
| -------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `--follow`, `-f`           | Continue streaming logs in real time.                                                                      |
| `--since <duration>`, `-s` | Fetch logs starting from a relative duration (e.g. `5m`, `1h`, `1h30m`) or timestamp (`2006-01-02T15:04`). |
| `--with-timestamps`, `-t`  | Prefix each line with an RFC3339 timestamp.                                                                |

## `kernel deploy history [app_name]`

Show deployment history for all apps or a specific app.

| Flag                       | Description                                                        |
| -------------------------- | ------------------------------------------------------------------ |
| `--limit <n>`              | Maximum number of deployments to return (default: 100, `0` = all). |
| `--output json`, `-o json` | Output raw JSON array.                                             |

## `kernel invoke <app> <action>`

Invoke an app action. By default the CLI returns immediately after the invocation is queued.

| Flag                        | Description                                                        |
| --------------------------- | ------------------------------------------------------------------ |
| `--version <version>`, `-v` | Target a specific app version (default: latest).                   |
| `--payload <json>`, `-p`    | Provide a JSON payload (stringified, max 64 KB).                   |
| `--sync`, `-s`              | Wait for completion (timeout after 60 s).                          |
| `--output json`, `-o json`  | Output JSONL (one JSON object per line for each invocation event). |

## `kernel app list`

List deployed app versions.

| Flag                       | Description              |
| -------------------------- | ------------------------ |
| `--name <app_name>`        | Filter by app name.      |
| `--version <version>`      | Filter by version label. |
| `--output json`, `-o json` | Output raw JSON array.   |

## `kernel app history <app_name>`

Show deployment history for a specific app.

| Flag                       | Description                                                        |
| -------------------------- | ------------------------------------------------------------------ |
| `--limit <n>`              | Maximum number of deployments to return (default: 100, `0` = all). |
| `--output json`, `-o json` | Output raw JSON array.                                             |

## `kernel logs <app_name>`

Tail app logs.

| Flag                       | Description                                                                     |
| -------------------------- | ------------------------------------------------------------------------------- |
| `--version <version>`      | Select an app version (default: latest).                                        |
| `--follow`, `-f`           | Stream logs continuously.                                                       |
| `--since <duration>`, `-s` | Fetch logs from a duration or timestamp (same formats as `kernel deploy logs`). |
| `--with-timestamps`        | Include timestamps in each line.                                                |

----
url: https://www.kernel.sh/docs/api-reference/deployments/stream-deployment-events-via-sse
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.deployments.follow('id');

console.log(response);
```

```
{
  "event": "<string>",
  "timestamp": "2023-11-07T05:31:56Z",
  "message": "<string>"
}
```

GET

/

deployments

/

{id}

/

events

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.deployments.follow('id');

console.log(response);
```

```
{
  "event": "<string>",
  "timestamp": "2023-11-07T05:31:56Z",
  "message": "<string>"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

The deployment ID to follow.

#### Query Parameters

[​](#parameter-since)

since

string

Show logs since the given time (RFC timestamps or durations like 5m).

Example:

`"2025-06-20T12:00:00Z"`

#### Response

SSE stream of deployment state updates and logs.

* Option 1

* Option 2

* Option 3

* Option 4

* Option 5

Union type representing any deployment event.

[Delete a deployment](https://www.kernel.sh/docs/api-reference/deployments/delete-a-deployment)

[Previous](https://www.kernel.sh/docs/api-reference/deployments/delete-a-deployment)

[Read file contents](https://www.kernel.sh/docs/api-reference/browser-filesystem/read-file-contents)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/read-file-contents)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-computer-controls/simulate-a-mouse-click-action-on-the-browser-instance
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.clickMouse('id', { x: 0, y: 0 });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

click\_mouse

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.clickMouse('id', { x: 0, y: 0 });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-x)

x

integer

required

X coordinate of the click position

[​](#body-y)

y

integer

required

Y coordinate of the click position

[​](#body-button)

button

enum\<string>

Mouse button to interact with

Available options

:

`left`,

`right`,

`middle`,

`back`,

`forward`

[​](#body-click-type)

click\_type

enum\<string>

Type of click action

Available options

:

`down`,

`up`,

`click`

[​](#body-hold-keys)

hold\_keys

string\[]

Modifier keys to hold during the click

[​](#body-num-clicks)

num\_clicks

integer

default:1

Number of times to repeat the click

#### Response

Mouse action performed

[Stop a browser session replay recording](https://www.kernel.sh/docs/api-reference/browser-replays/stop-a-browser-session-replay-recording)

[Previous](https://www.kernel.sh/docs/api-reference/browser-replays/stop-a-browser-session-replay-recording)

[Move the mouse cursor to the specified coordinates on the browser instance](https://www.kernel.sh/docs/api-reference/browser-computer-controls/move-the-mouse-cursor-to-the-specified-coordinates-on-the-browser-instance)

[Next](https://www.kernel.sh/docs/api-reference/browser-computer-controls/move-the-mouse-cursor-to-the-specified-coordinates-on-the-browser-instance)

Ctrl+I

----
url: https://www.kernel.sh/docs/integrations/computer-use/openagi
----

The [OpenAGI](https://lux.agiopen.org/) Lux Model is a computer-use model that enables AI agents to interact with computers the way humans do. Lux operates in a continuous action-observation loop: it receives a task, analyzes a screenshot of the current screen state, generates the next UI interaction (click, type, etc.), and repeats until the goal is achieved. By integrating OpenAGI with Kernel, you can run these AI-powered browser automations on cloud-hosted infrastructure, eliminating the need for local browser management and enabling scalable, reliable computer-using agents.

## [​](#getting-started)Getting started

To get started with OpenAGI Lux and Kernel:

1. Get your `OAGI_API_KEY` on the [OpenAGI Developer Platform](https://developer.agiopen.org/)
2. Get your `KERNEL_API_KEY` from the [Kernel Dashboard](https://dashboard.onkernel.com/)

For more information about Lux’s capabilities, visit the [OpenAGI Lux Documentation](https://lux.agiopen.org/).

## [​](#quick-setup-with-computer-use)Quick setup with Computer Use

The fastest way to get started is using the Kernel CLI’s built-in OpenAGI template:

```
kernel create --template openagi-computer-use --language python
cd <your-app-name>
kernel deploy main.py --env-file .env
```

This creates a pre-configured OpenAGI app with both `AsyncDefaultAgent` and `TaskerAgent` implementations ready to deploy.

## [​](#benefits-of-using-kernel-with-openagi)Benefits of using Kernel with OpenAGI

* **No local browser management**: Run OpenAGI automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel for concurrent AI agents
* **Stealth mode**: Built-in anti-detection features for reliable web interactions
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your OpenAGI agents with real-time browser viewing
* **Cloud infrastructure**: Run computationally intensive AI agents without local resource constraints

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your OpenAGI automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your OpenAGI app to Kernel

----
url: https://www.kernel.sh/docs/api-reference/extensions/list-browser-extensions
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const extensions = await client.extensions.list();

console.log(extensions);
```

```
[
  {
    "id": "<string>",
    "created_at": "2023-11-07T05:31:56Z",
    "size_bytes": 123,
    "name": "<string>",
    "last_used_at": "2023-11-07T05:31:56Z"
  }
]
```

GET

/

extensions

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const extensions = await client.extensions.list();

console.log(extensions);
```

```
[
  {
    "id": "<string>",
    "created_at": "2023-11-07T05:31:56Z",
    "size_bytes": 123,
    "name": "<string>",
    "last_used_at": "2023-11-07T05:31:56Z"
  }
]
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Response

List of extensions

[​](#response-items-id)

id

string

required

Unique identifier for the extension

[​](#response-items-created-at)

created\_at

string\<date-time>

required

Timestamp when the extension was created

[​](#response-items-size-bytes)

size\_bytes

integer

required

Size of the extension archive in bytes

[​](#response-items-name-one-of-0)

name

string | null

Optional, easier-to-reference name for the extension. Must be unique within the organization.

[​](#response-items-last-used-at-one-of-0)

last\_used\_at

string\<date-time> | null

Timestamp when the extension was last used

[Stream login flow events via SSE](https://www.kernel.sh/docs/api-reference/managed-auth/stream-login-flow-events-via-sse)

[Previous](https://www.kernel.sh/docs/api-reference/managed-auth/stream-login-flow-events-via-sse)

[Upload a browser extension](https://www.kernel.sh/docs/api-reference/extensions/upload-a-browser-extension)

[Next](https://www.kernel.sh/docs/api-reference/extensions/upload-a-browser-extension)

Ctrl+I

----
url: https://www.kernel.sh/docs/reference/cli/create
----

## `kernel create`

Create a new Kernel application from a template. The CLI provides an interactive prompt to guide you through selecting a language and template, or you can specify all options via flags.

| Flag                          | Description                                                   |
| ----------------------------- | ------------------------------------------------------------- |
| `--name <name>`, `-n`         | Name of the application directory to create.                  |
| `--language <language>`, `-l` | Programming language: `typescript` (`ts`) or `python` (`py`). |
| `--template <template>`, `-t` | Template to scaffold (see available templates below).         |

## Available templates

### TypeScript templates

### Python templates

## Examples

## Next steps

After creating your app:

1. **Navigate to the project directory:**
2. **Install dependencies:**
3. **Authenticate with Kernel:**
4. **Deploy your app:**
5. **Invoke your app:**

----
url: https://www.kernel.sh/docs/integrations/claude-agent-sdk
----

The [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview) provides a powerful way to build AI agents that can autonomously perform tasks. By integrating the Claude Agent SDK with Kernel, you can create agents that browse the web and interact with websites using cloud-hosted browser infrastructure. This integration combines Claude’s agent capabilities with Kernel’s Playwright Execution API to enable browser automation without managing local browser infrastructure.

## [​](#quick-setup-with-claude-agent-sdk)Quick setup with Claude Agent SDK

Get started with Claude Agent SDK and Kernel using our pre-configured app template:

```
kernel create --template claude-agent-sdk
```

Choose `TypeScript` or `Python` as the programming language. Then follow the [Quickstart guide](https://www.kernel.sh/docs/quickstart) to deploy and run your Claude Agent SDK automation on Kernel’s infrastructure.

## [​](#prerequisites)Prerequisites

### [​](#claude-code-installation)Claude Code Installation

The Claude Agent SDK requires Claude Code to be installed. Choose one of the following methods:

```
# Homebrew (macOS)
brew install --cask claude-code

# pnpm (cross-platform)
pnpm add -g @anthropic-ai/claude-code

# macOS/Linux/WSL
curl -fsSL https://claude.ai/install.sh | bash
```

See the [official installation guide](https://platform.claude.com/docs/en/agent-sdk/overview#get-started) for Windows and other options.

When deploying to Kernel, the app automatically installs Claude Code on the remote infrastructure.

### [​](#api-keys)API Keys

You’ll need:

* **ANTHROPIC\_API\_KEY**: Get from the [Anthropic Console](https://console.anthropic.com/)
* **KERNEL\_API\_KEY**: Get from the [Kernel Dashboard](https://dashboard.onkernel.com/api-keys)

## [​](#running-locally)Running locally

```
# Install dependencies
pnpm install

# Set up environment variables
cp .env.example .env
# Edit .env with your API keys

# Run with default task
pnpm exec tsx index.ts

# Run with custom task
pnpm exec tsx index.ts "Go to duckduckgo.com and search for 'Kernel browser automation'"
```

## [​](#deploying-to-kernel)Deploying to Kernel

Deploy and invoke the app on Kernel’s infrastructure:

```
# Login to Kernel
kernel login

# Deploy the app with environment variables
kernel deploy index.ts --env-file .env

# Invoke the action (logs stream automatically)
kernel invoke ts-claude-agent-sdk agent-task -p '{"task": "Go to https://news.ycombinator.com and get the top 3 stories"}'
```

## [​](#how-it-works)How it works

1. **Browser Creation**: A Kernel browser session is created with stealth mode enabled
2. **MCP Server**: An in-process MCP server is created with an `execute_playwright` tool
3. **Agent Execution**: The Claude Agent SDK runs with access to the Playwright tool
4. **Task Completion**: Claude autonomously uses the tool to complete the given task
5. **Cleanup**: The browser session is deleted when done

## [​](#example-tasks)Example tasks

```
# Get top Hacker News stories
"Go to https://news.ycombinator.com and tell me the top 3 stories"

# Search for something
"Go to duckduckgo.com and search for 'Kernel browser automation'"

# Extract data from a page
"Go to https://github.com/trending and list the top 5 trending repositories"
```

## [​](#benefits-of-using-kernel-with-claude-agent-sdk)Benefits of using Kernel with Claude Agent SDK

* **No local browser management**: Run Claude Agent SDK automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel for concurrent AI agents
* **Stealth mode**: Built-in anti-detection features for reliable web interactions
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your Claude agents with real-time browser viewing
* **Cloud infrastructure**: Run computationally intensive AI agents without local resource constraints

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your Claude Agent SDK automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn about [Playwright Execution](https://www.kernel.sh/docs/browsers/playwright-execution) for running Playwright code in the browser VM
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Claude Agent SDK app to Kernel

----
url: https://www.kernel.sh/docs/api-reference/browser-computer-controls/write-text-to-the-clipboard-on-the-browser-instance
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.writeClipboard('id', { text: 'text' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

write

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.writeClipboard('id', { text: 'text' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-text)

text

string

required

Text to write to the system clipboard

#### Response

Text written to clipboard successfully

[Read text from the clipboard on the browser instance](https://www.kernel.sh/docs/api-reference/browser-computer-controls/read-text-from-the-clipboard-on-the-browser-instance)

[Previous](https://www.kernel.sh/docs/api-reference/browser-computer-controls/read-text-from-the-clipboard-on-the-browser-instance)

[List apps](https://www.kernel.sh/docs/api-reference/apps/list-apps)

[Next](https://www.kernel.sh/docs/api-reference/apps/list-apps)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-computer-controls/move-the-mouse-cursor-to-the-specified-coordinates-on-the-browser-instance
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.moveMouse('id', { x: 0, y: 0 });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

move\_mouse

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.moveMouse('id', { x: 0, y: 0 });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-x)

x

integer

required

X coordinate to move the cursor to

[​](#body-y)

y

integer

required

Y coordinate to move the cursor to

[​](#body-hold-keys)

hold\_keys

string\[]

Modifier keys to hold during the move

[​](#body-smooth)

smooth

boolean

default:true

Use human-like Bezier curve path instead of instant mouse movement.

[​](#body-duration-ms)

duration\_ms

integer

Target total duration in milliseconds for the mouse movement when smooth=true. Omit for automatic timing based on distance.

Required range

: `50 <= x <= 5000`

#### Response

Mouse cursor moved

[Simulate a mouse click action on the browser instance](https://www.kernel.sh/docs/api-reference/browser-computer-controls/simulate-a-mouse-click-action-on-the-browser-instance)

[Previous](https://www.kernel.sh/docs/api-reference/browser-computer-controls/simulate-a-mouse-click-action-on-the-browser-instance)

[Capture a screenshot of the browser instance](https://www.kernel.sh/docs/api-reference/browser-computer-controls/capture-a-screenshot-of-the-browser-instance)

[Next](https://www.kernel.sh/docs/api-reference/browser-computer-controls/capture-a-screenshot-of-the-browser-instance)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-file
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.deleteFile('id', { path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

delete\_file

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.deleteFile('id', { path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

#### Response

File deleted

[Create a new directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/create-a-new-directory)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/create-a-new-directory)

[Delete a directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-directory)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-directory)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/invocations/invoke-an-action
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const invocation = await client.invocations.create({
  action_name: 'analyze',
  app_name: 'my-app',
  version: '1.0.0',
});

console.log(invocation.id);
```

```
{
  "id": "rr33xuugxj9h0bkf1rdt2bet",
  "action_name": "analyze",
  "status": "queued",
  "status_reason": "Invocation queued for execution",
  "output": "{\"result\":\"success\",\"data\":\"processed input\"}"
}
```

POST

/

invocations

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const invocation = await client.invocations.create({
  action_name: 'analyze',
  app_name: 'my-app',
  version: '1.0.0',
});

console.log(invocation.id);
```

```
{
  "id": "rr33xuugxj9h0bkf1rdt2bet",
  "action_name": "analyze",
  "status": "queued",
  "status_reason": "Invocation queued for execution",
  "output": "{\"result\":\"success\",\"data\":\"processed input\"}"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Body

application/json

Invocation parameters

[​](#body-app-name)

app\_name

string

required

Name of the application

Example:

`"my-app"`

[​](#body-version)

version

string

default:latest

required

Version of the application

Example:

`"1.0.0"`

[​](#body-action-name)

action\_name

string

required

Name of the action to invoke

Example:

`"analyze"`

[​](#body-payload)

payload

string

Input data for the action, sent as a JSON string.

Example:

`"{\"data\":\"example input\"}"`

[​](#body-async)

async

boolean

default:false

If true, invoke asynchronously. When set, the API responds 202 Accepted with status "queued".

Example:

`true`

[​](#body-async-timeout-seconds)

async\_timeout\_seconds

integer

default:900

Timeout in seconds for async invocations (min 10, max 3600). Only applies when async is true.

Required range

: `10 <= x <= 3600`

Example:

`600`

#### Response

Invocation created successfully

[​](#response-id)

id

string

required

ID of the invocation

Example:

`"rr33xuugxj9h0bkf1rdt2bet"`

[​](#response-action-name)

action\_name

string

required

Name of the action invoked

Example:

`"analyze"`

[​](#response-status)

status

enum\<string>

required

Status of the invocation

Available options

:

`queued`,

`running`,

`succeeded`,

`failed`

Example:

`"queued"`

[​](#response-status-reason)

status\_reason

string

Status reason

Example:

`"Invocation queued for execution"`

[​](#response-output)

output

string

The return value of the action that was invoked, rendered as a JSON string. This could be: string, number, boolean, array, object, or null.

Example:

`"{\"result\":\"success\",\"data\":\"processed input\"}"`

[List invocations](https://www.kernel.sh/docs/api-reference/invocations/list-invocations)

[Previous](https://www.kernel.sh/docs/api-reference/invocations/list-invocations)

[Get invocation details](https://www.kernel.sh/docs/api-reference/invocations/get-invocation-details)

[Next](https://www.kernel.sh/docs/api-reference/invocations/get-invocation-details)

Ctrl+I

----
url: https://www.kernel.sh/docs/integrations/agent-browser
----

[Agent Browser](https://github.com/vercel-labs/agent-browser) is a headless browser automation CLI for AI agents built by Vercel. It provides a fast Rust CLI with Node.js fallback, making it ideal for AI-powered browser automation. By integrating with Kernel, you can run Agent Browser automations with cloud-hosted browsers.

## Using the native Kernel provider

Agent Browser has built-in support for Kernel as a cloud browser provider. This is the simplest way to use Kernel with Agent Browser.

### Quick start

Use the `-p` flag to enable Kernel:

Get your API key from the [Kernel Dashboard](https://dashboard.onkernel.com/api-keys).

### Configuration options

Configure Kernel via environment variables:

| Variable                 | Description                                                 | Default |
| ------------------------ | ----------------------------------------------------------- | ------- |
| `AGENT_BROWSER_PROVIDER` | Set to `kernel` as an alternative to the `-p kernel` flag   | (none)  |
| `KERNEL_HEADLESS`        | Run browser in headless mode (`true`/`false`)               | `false` |
| `KERNEL_STEALTH`         | Enable stealth mode to avoid bot detection (`true`/`false`) | `true`  |
| `KERNEL_TIMEOUT_SECONDS` | Session timeout in seconds                                  | `300`   |
| `KERNEL_PROFILE_NAME`    | Browser profile name for persistent cookies/logins          | (none)  |

### Profile persistence

When `KERNEL_PROFILE_NAME` is set, the profile will be created if it doesn’t already exist. Cookies, logins, and session data are automatically saved back to the profile when the browser session ends, making them available for future sessions.

## Connecting via CDP (alternative)

Use this approach when you need full control of the Kernel browser session creation logic beyond what the agent-browser environment variables support.

## Programmatic usage

Use this approach if you want to use agent-browser as an alternative to Playwright within a Node.js or Python application while maintaining programmatic control over browser session lifecycle.

```
import subprocess
from kernel import Kernel

kernel = Kernel()
browser = kernel.browsers.create(stealth=True)

print(f"Live view url: {browser.browser_live_view_url}")

try:
    subprocess.run(["agent-browser", "connect", browser.cdp_ws_url], check=True)
    subprocess.run(["agent-browser", "open", "https://example.com"], check=True)
    subprocess.run(["agent-browser", "snapshot"], check=True)
    subprocess.run(["agent-browser", "close"], check=True)
finally:
    kernel.browsers.delete_by_id(browser.session_id)
```

## Benefits of using Kernel with Agent Browser

## Next steps

----
url: https://www.kernel.sh/docs/browsers/ssh
----

SSH into a running Kernel browser VM for debugging, running commands, or setting up port forwarding.

## Forward local dev server to browser

A common use case is exposing a local development server to the remote Kernel browser. This lets the browser access `localhost` URLs that point to your local machine:

## Prerequisites

The `kernel browsers ssh` command requires [websocat](https://github.com/vi/websocat) to be installed locally:

## Basic usage

Open an interactive SSH shell to a browser VM:

By default, this generates an ephemeral ed25519 SSH keypair for the session. The keypair is automatically cleaned up when the session ends.

## Using an existing SSH key

Specify an existing SSH private key instead of generating an ephemeral one:

## Port forwarding

Port forwarding uses standard SSH syntax.

### Local forwarding (`-L`)

Forward a local port to a port on the VM. Useful for accessing services running inside the VM from your local machine:

### Remote forwarding (`-R`)

Forward a VM port to a port on your local machine. Useful for exposing a local development server to the browser:

This allows code running in the browser to access `localhost:8080` and reach your local development server.

## Setup only

Configure SSH on the VM without opening a connection:

This installs and configures the SSH server on the VM, then prints the manual connection command. Useful if you want to connect with your own SSH client or configuration.

## Flags

| Flag                          | Description                                                    |
| ----------------------------- | -------------------------------------------------------------- |
| `-i, --identity <path>`       | Path to SSH private key (generates ephemeral if not provided). |
| `-L, --local-forward <spec>`  | Local port forwarding (`localport:host:remoteport`).           |
| `-R, --remote-forward <spec>` | Remote port forwarding (`remoteport:host:localport`).          |
| `--setup-only`                | Setup SSH on VM without connecting.                            |

----
url: https://www.kernel.sh/docs/reference/cli/extensions
----

Manage browser extensions for use with Kernel browsers.

## Extension Management

### `kernel extensions list`

List all extensions in your organization. **Output includes:**

**Example:**

### `kernel extensions upload <directory>`

Upload an unpacked browser extension directory or zip file.

| Flag            | Description                                                                      |
| --------------- | -------------------------------------------------------------------------------- |
| `--name <name>` | Optional unique name for the extension. Must be unique within your organization. |

**Example:**

### `kernel extensions download <id-or-name>`

Download an extension archive by ID or name.

| Flag          | Description                              |
| ------------- | ---------------------------------------- |
| `--to <path>` | Output path for the downloaded zip file. |

**Example:**

### `kernel extensions delete <id-or-name>`

Delete an extension by ID or name.

| Flag          | Description               |
| ------------- | ------------------------- |
| `--yes`, `-y` | Skip confirmation prompt. |

**Example:**

### `kernel extensions download-web-store <url>`

Download and unpack an extension directly from the Chrome Web Store.

| Flag              | Description                                             |
| ----------------- | ------------------------------------------------------- |
| `--to <path>`     | Output directory for the unpacked extension.            |
| `--os <platform>` | Target OS: `mac`, `win`, or `linux` (default: `linux`). |

**Example:**

After downloading, you can upload the extension to Kernel:

### `kernel extensions build-web-bot-auth`

Build Cloudflare’s [Web Bot Auth](https://www.kernel.sh/docs/browsers/bot-detection/web-bot-auth) browser extension for signing HTTP requests with RFC 9421 signatures.

| Flag              | Description                                                                         |
| ----------------- | ----------------------------------------------------------------------------------- |
| `--to <dir>`      | Output directory for the built extension (required).                                |
| `--key <path>`    | Path to JWK file with Ed25519 signing key (defaults to RFC9421 test key).           |
| `--upload <name>` | Upload the extension to Kernel with specified name (e.g., —upload my-web-bot-auth). |

**Examples:**

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/list-files-in-a-directory
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.fs.listFiles('id', { path: '/J!' });

console.log(response);
```

```
[
  {
    "name": "<string>",
    "path": "<string>",
    "size_bytes": 123,
    "is_dir": true,
    "mod_time": "2023-11-07T05:31:56Z",
    "mode": "<string>"
  }
]
```

list\_files

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.fs.listFiles('id', { path: '/J!' });

console.log(response);
```

```
[
  {
    "name": "<string>",
    "path": "<string>",
    "size_bytes": 123,
    "is_dir": true,
    "mod_time": "2023-11-07T05:31:56Z",
    "mode": "<string>"
  }
]
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Query Parameters

[​](#parameter-path)

path

string

required

Absolute directory path.

Pattern: `^/.*`

#### Response

Directory listing

[​](#response-items-name)

name

string

required

Base name of the file or directory.

[​](#response-items-path)

path

string

required

Absolute path.

[​](#response-items-size-bytes)

size\_bytes

integer

required

Size in bytes. 0 for directories.

[​](#response-items-is-dir)

is\_dir

boolean

required

Whether the path is a directory.

[​](#response-items-mod-time)

mod\_time

string\<date-time>

required

Last modification time.

[​](#response-items-mode)

mode

string

required

File mode bits (e.g., "drwxr-xr-x" or "-rw-r--r--").

[Write or create a file](https://www.kernel.sh/docs/api-reference/browser-filesystem/write-or-create-a-file)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/write-or-create-a-file)

[Create a new directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/create-a-new-directory)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/create-a-new-directory)

⌘I

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/get-information-about-a-file-or-directory
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.fs.fileInfo('id', { path: '/J!' });

console.log(response.is_dir);
```

```
{
  "name": "<string>",
  "path": "<string>",
  "size_bytes": 123,
  "is_dir": true,
  "mod_time": "2023-11-07T05:31:56Z",
  "mode": "<string>"
}
```

file\_info

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.fs.fileInfo('id', { path: '/J!' });

console.log(response.is_dir);
```

```
{
  "name": "<string>",
  "path": "<string>",
  "size_bytes": 123,
  "is_dir": true,
  "mod_time": "2023-11-07T05:31:56Z",
  "mode": "<string>"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Query Parameters

[​](#parameter-path)

path

string

required

Absolute path of the file or directory.

Pattern: `^/.*`

#### Response

File information

[​](#response-name)

name

string

required

Base name of the file or directory.

[​](#response-path)

path

string

required

Absolute path.

[​](#response-size-bytes)

size\_bytes

integer

required

Size in bytes. 0 for directories.

[​](#response-is-dir)

is\_dir

boolean

required

Whether the path is a directory.

[​](#response-mod-time)

mod\_time

string\<date-time>

required

Last modification time.

[​](#response-mode)

mode

string

required

File mode bits (e.g., "drwxr-xr-x" or "-rw-r--r--").

[Set file or directory permissions/ownership](https://www.kernel.sh/docs/api-reference/browser-filesystem/set-file-or-directory-permissionsownership)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/set-file-or-directory-permissionsownership)

[Move or rename a file or directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/move-or-rename-a-file-or-directory)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/move-or-rename-a-file-or-directory)

Ctrl+I

----
url: https://www.kernel.sh/docs/integrations/vercel/ai-sdk
----

## Overview

The `@onkernel/ai-sdk` package provides Vercel AI SDK-compatible tools for browser automation powered by Kernel. This package exposes a Playwright execution tool that allows LLMs to browse the web, interact with websites, and perform automation tasks through natural language instructions. With this tool, AI agents can execute Playwright code on Kernel’s remote browsers, enabling powerful browser automation capabilities in your AI-powered applications.

## Installation

Install the package along with its peer dependencies:

## Prerequisites

Before using the AI SDK tool, you’ll need:

1. **Kernel API Key** - Obtain from the [Kernel Dashboard](https://dashboard.onkernel.com/) or the [Vercel Marketplace integration](https://www.kernel.sh/docs/integrations/vercel/marketplace)
2. **AI Model Provider** - An API key for your chosen LLM provider (OpenAI, Anthropic, etc.)
3. **Kernel Browser Session** - A running browser session created via the Kernel SDK

## How It Works

The `playwrightExecuteTool` creates a Vercel AI SDK tool that:

1. Accepts natural language instructions from an LLM
2. Converts those instructions into Playwright code
3. Executes the code on a Kernel remote browser
4. Returns the results back to the LLM

This enables AI agents to autonomously browse websites, extract data, and perform complex automation tasks.

## Usage with `generateText()`

The simplest way to use the AI SDK tool is with Vercel’s `generateText()` function:

## Usage with `Agent()`

For more complex, multi-step automation tasks, use the Vercel AI SDK’s `Agent()` class. Agents can autonomously plan and execute a series of actions to accomplish a goal:

```
import 'dotenv/config';
import { openai } from '@ai-sdk/openai';
import { playwrightExecuteTool } from '@onkernel/ai-sdk';
import { Kernel } from '@onkernel/sdk';
import { Experimental_Agent as Agent, stepCountIs } from 'ai';

const kernel = new Kernel({
  apiKey: process.env.KERNEL_API_KEY,
});

const browser = await kernel.browsers.create({});
const sessionId = browser.session_id;

console.log('Browser session started:', sessionId);
console.log('Browser session URL:', browser.browser_live_view_url);

// Initialize the AI agent with GPT-5.1
const agent = new Agent({
  model: openai('gpt-5.1'),
  tools: {
    playwright_execute: playwrightExecuteTool({
      client: kernel,
      sessionId
    }),
  },
  stopWhen: stepCountIs(20), // Maximum 20 steps
  system: `You are a browser automation expert. You help users execute tasks in their browser using Playwright.`,
});

// Execute the agent with the user's task
const result = await agent.generate({
  prompt: 'Go to news.ycombinator.com and get the titles of the top 3 posts.',
});

console.log('Agent response:', result.text);

await kernel.browsers.deleteByID(browser.session_id);
```

## Tool Parameters

The `playwrightExecuteTool` function accepts the following parameters:

### Tool Input Schema

The generated tool accepts the following input from the LLM:

Under the hood, the tool calls:

So, any code you can run through the SDK can be run via the tool.

## Additional Resources

----
url: https://www.kernel.sh/docs/integrations/valtown
----

[Val Town](https://www.val.town/) is a serverless platform to run Typescript automations. You can think of it like Zapier for software developers. Because Val Town can’t launch a local browser, Kernel lets you use tools like Puppeteer or Playwright on Val Town by connecting to a remote browser session hosted on Kernel’s infrastructure.

## [​](#quick-start-with-puppeteer)Quick start with Puppeteer

1. Create a free [Kernel account](https://dashboard.onkernel.com/sign-up) and generate an API key from Settings → API Keys
2. Remix this [Kernel starter val](https://www.val.town/x/onkernel/kernel_starter)
3. Add it to your Val Town val’s Environment Variables (left sidebar) as `KERNEL_API_KEY`
4. Click **Run** on `puppeteer.ts`
5. View logs for output

## [​](#quick-start-with-playwright)Quick start with Playwright

Kernel also supports Playwright sessions. The steps are nearly identical:

1. Remix this [Kernel starter val](https://www.val.town/x/onkernel/kernel_starter)
2. Add your `KERNEL_API_KEY` to Environment Variables
3. Set `TMPDIR` to `/tmp` to avoid Playwright file-system warnings
4. Click **Run** on `playwright.ts`
5. Check the logs for output

----
url: https://www.kernel.sh/docs/api-reference/browser-playwright/execute-playwrighttypescript-code-against-the-browser
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.playwright.execute('id', { code: 'code' });

console.log(response.success);
```

```
{
  "success": true,
  "result": "<unknown>",
  "error": "<string>",
  "stdout": "<string>",
  "stderr": "<string>"
}
```

POST

/

browsers

/

{id}

/

playwright

/

execute

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.playwright.execute('id', { code: 'code' });

console.log(response.success);
```

```
{
  "success": true,
  "result": "<unknown>",
  "error": "<string>",
  "stdout": "<string>",
  "stderr": "<string>"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

Request to execute Playwright code

[​](#body-code)

code

string

required

TypeScript/JavaScript code to execute. The code has access to 'page', 'context', and 'browser' variables. It runs within a function, so you can use a return statement at the end to return a value. This value is returned as the `result` property in the response. Example: "await page.goto('[https://example.com](https://example.com/)'); return await page.title();"

[​](#body-timeout-sec)

timeout\_sec

integer

default:60

Maximum execution time in seconds. Default is 60.

Required range

: `1 <= x <= 300`

#### Response

Code executed successfully

Result of Playwright code execution

[​](#response-success)

success

boolean

required

Whether the code executed successfully

[​](#response-result)

result

any

The value returned by the code (if any)

[​](#response-error)

error

string

Error message if execution failed

[​](#response-stdout)

stdout

string

Standard output from the execution

[​](#response-stderr)

stderr

string

Standard error from the execution

[Resize a PTY-backed process terminal](https://www.kernel.sh/docs/api-reference/browser-processes/resize-a-pty-backed-process-terminal)

[Previous](https://www.kernel.sh/docs/api-reference/browser-processes/resize-a-pty-backed-process-terminal)

[Stream log files on the browser instance via SSE](https://www.kernel.sh/docs/api-reference/browser-logs/stream-log-files-on-the-browser-instance-via-sse)

[Next](https://www.kernel.sh/docs/api-reference/browser-logs/stream-log-files-on-the-browser-instance-via-sse)

Ctrl+I

----
url: https://www.kernel.sh/docs/integrations/laminar
----

[Laminar](https://www.laminar.sh/) is an open-source observability and evaluation platform for autonomous AI agents. You can create a cloud account or self-host Laminar for your infrastructure. By integrating Laminar with Kernel, you can trace and monitor your browser automations with full visibility into LLM calls, browser actions, session recordings, and performance metrics.

## Why use Laminar with Kernel?

## Prerequisites

Before integrating Laminar with Kernel, you’ll need:

1. A [Kernel account](https://dashboard.onkernel.com/sign-up) with a Kernel API Key
2. A [Laminar account](https://www.laminar.sh/) and project
3. Your Laminar project API key from the Project Settings page

## Installation

## Getting your Laminar API key

1. Log in to your [Laminar dashboard](https://www.laminar.sh/)
2. Navigate to **Project Settings**
3. Generate a new API key in your project
4. Copy your **Project API Key**
5. Set it as an environment variable:

## Browser Agent Framework Examples

Select your browser automation framework to enable Laminar tracing with Kernel:

### Playwright

Playwright is a popular low-level browser automation framework. Here’s how to use it with Laminar and Kernel:

### Browser Use

[Browser Use](https://github.com/browser-use/browser-use) is an AI browser agent framework. Here’s how to integrate it with Laminar and Kernel:

```
import os
import asyncio
from lmnr import Laminar, observe
from browser_use import Agent, Browser, ChatOpenAI
from kernel import Kernel

# Initialize Laminar
Laminar.initialize(project_api_key=os.environ["LMNR_PROJECT_API_KEY"])

@observe()
async def main():
    # Initialize Kernel and create a browser
    client = Kernel()
    kernel_browser = client.browsers.create(stealth=True, viewport={'width': 1920, 'height': 1080})

    print(f"Live view url: {kernel_browser.browser_live_view_url}")

    # Configure Browser Use with Kernel's CDP URL
    browser = Browser(
        cdp_url=kernel_browser.cdp_ws_url,
        headless=False,
        window_size={'width': 1920, 'height': 1080},
        viewport={'width': 1920, 'height': 1080},
        device_scale_factor=1.0
    )

    # Initialize the model
    llm = ChatOpenAI(
        model="gpt-4.1",
    )

    # Create and run the agent with job extraction task
    agent = Agent(
        task="""1. Go to https://www.onkernel.com/docs
        2. Navigate to the main Jobs page
        3. Extract all the job posting URLs. List each URL you find.""",
        llm=llm,
        browser_session=browser
    )

    result = await agent.run()
    print(f"Job URLs found:\n{result.final_result()}")

    # Flush traces to Laminar
    Laminar.flush()

    # Delete the browser for those who left open the live view url
    client.browsers.delete_by_id(kernel_browser.session_id)

asyncio.run(main())
```

### Stagehand

[Stagehand](https://github.com/browserbase/stagehand) is an AI browser automation framework. Here’s how to use it with Laminar and Kernel:

## Tracing Kernel Apps & Computer Controls

When you use Kernel’s [App platform](https://www.kernel.sh/docs/apps/develop) or [Computer controls](https://www.kernel.sh/docs/browsers/computer-controls), Laminar will automatically trace the computer and process interactions. In addition, you don’t have to manually `observe` your kernel `app.actions` or worry about manual trace flushing inside your Kernel apps.

### Example Kernel app with Laminar tracing

To deploy this example on Kernel, follow the steps in [Kernel’s app deployment guide](https://www.kernel.sh/docs/apps/deploy).

## Viewing traces in Laminar

View your traces in the Laminar UI’s traces tab to see synchronized browser session recordings and agent execution steps. After running your automation:

1. Log in to your [Laminar dashboard](https://www.lmnr.ai/)
2. Navigate to the **Traces** tab
3. Find your recent trace to view:

Timeline highlights indicate which step your agent is currently executing, making it easy to debug and optimize your automations.

## Next steps

----
url: https://www.kernel.sh/docs/integrations/browser-use
----

[Browser Use](https://github.com/browser-use/browser-use) is the AI browser agent that empowers anyone to automate repetitive online tasks, no code required. By integrating with Kernel, you can run Browser Use Agents and automations with cloud-hosted browsers.

## [​](#adding-kernel-to-existing-browser-use-implementations)Adding Kernel to existing Browser Use implementations

If you already have a Browser Use implementation, you can easily switch to using Kernel’s cloud browsers by updating your Browser definition.

### [​](#1-install-the-kernel-sdk)1. Install the Kernel SDK

```
uv add kernel
```

### [​](#2-initialize-kernel-and-create-a-browser)2. Initialize Kernel and create a browser

Import the libraries and create a cloud browser session:

```
from kernel import Kernel
from browser_use import Browser, Agent

# Initialize Kernel client
kernel = Kernel()

# Create a Kernel browser session
kernel_browser = kernel.browsers.create()
```

### [​](#3-update-your-browser-definition)3. Update your Browser definition

Replace your existing Browser initialization to use Kernel’s CDP URL and display settings:

```
# Update your Browser definition to use Kernel's CDP URL
browser = Browser(
    cdp_url=kernel_browser.cdp_ws_url,
    headless=False,
    window_size={'width': 1920, 'height': 1080},
    viewport={'width': 1920, 'height': 1080},
    device_scale_factor=1.0
)
```

Browser Use supports a wide range of browser configuration parameters. See the full list in the [Browser Use docs](https://docs.browser-use.com/customize/browser/all-parameters). When running on Kernel, remember that browsers must use one of Kernel’s supported viewport sizes and refresh rates. See [Viewports](https://www.kernel.sh/browsers/viewport) for the supported configurations.

### [​](#4-create-and-run-your-agent)4. Create and run your agent

Use your existing Agent setup with the Kernel-powered browser:

```
# Use with your existing Agent setup
agent = Agent(
    task="Your automation task",
    llm=your_llm_instance,
    browser_session=browser
)

# Run your automation
result = agent.run()

# Clean up
kernel.browsers.delete_by_id(kernel_browser.session_id)
```

If you’re using Browser Use versions `< 0.7.9`, you may need to use a [custom resize class](https://github.com/onkernel/create-kernel-app/blob/main/templates/python/browser-use/session.py) to correct viewport sizing for the browser session. Here’s how to use it:

```
agent = Agent(
    task="Your automation task",
    llm=your_llm_instance,
    browser_session=BrowserSessionCustomResize(cdp_url=kernel_browser.cdp_ws_url)
)
```

## [​](#quick-setup-with-our-browser-use-example-app)Quick setup with our Browser Use example app

Alternatively, you can use our Kernel app template that includes a pre-configured Browser Use integration:

```
kernel create --name my-browser-use-app --language python --template browser-use
```

Then follow the [Quickstart guide](https://www.kernel.sh/docs/quickstart) to deploy and run your Browser Use automation on Kernel’s infrastructure.

## [​](#benefits-of-using-kernel-with-browser-use)Benefits of using Kernel with Browser Use

* **No local browser management**: Run automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel
* **Stealth mode**: Built-in anti-detection features for web scraping
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your automations with real-time browser viewing

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Browser Use app to Kernel

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/upload-a-zip-archive-and-extract-it
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.uploadZip('id', {
  dest_path: '/J!',
  zip_file: fs.createReadStream('path/to/file'),
});
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

upload\_zip

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.uploadZip('id', {
  dest_path: '/J!',
  zip_file: fs.createReadStream('path/to/file'),
});
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

multipart/form-data

[​](#body-zip-file)

zip\_file

file

required

[​](#body-dest-path)

dest\_path

string

required

Absolute destination directory to extract the archive to.

Pattern: `^/.*`

#### Response

Zip uploaded and extracted successfully

[Upload one or more files](https://www.kernel.sh/docs/api-reference/browser-filesystem/upload-one-or-more-files)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/upload-one-or-more-files)

[Execute a command synchronously](https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-synchronously)

[Next](https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-synchronously)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/managed-auth/stream-login-flow-events-via-sse
----

```
{
  "event": "<string>",
  "timestamp": "2023-11-07T05:31:56Z",
  "flow_status": "IN_PROGRESS",
  "flow_step": "DISCOVERING",
  "flow_type": "LOGIN",
  "discovered_fields": [
    {
      "name": "email",
      "type": "email",
      "label": "Email address",
      "selector": "input#email",
      "placeholder": "you@example.com",
      "required": true,
      "linked_mfa_type": "sms"
    }
  ],
  "mfa_options": [
    {
      "type": "sms",
      "label": "Text me a code",
      "target": "***-***-5678",
      "description": "We'll send a 6-digit code to your phone"
    }
  ],
  "pending_sso_buttons": [
    {
      "selector": "xpath=//button[contains(text(), 'Continue with Google')]",
      "provider": "google",
      "label": "Continue with Google"
    }
  ],
  "external_action_message": "<string>",
  "website_error": "<string>",
  "error_message": "<string>",
  "error_code": "<string>",
  "post_login_url": "<string>",
  "live_view_url": "<string>",
  "hosted_url": "<string>"
}
```

----
url: https://www.kernel.sh/docs/integrations/vercel/overview
----

## [​](#vercel-+-kernel)Vercel + Kernel

Kernel and Vercel have partnered to provide seamless browser automation capabilities for your Vercel applications. Our integration offers two powerful ways to add browser automation to your projects:

### [​](#ai-sdk-tool-for-browser-automation)AI SDK Tool for Browser Automation

The `@onkernel/ai-sdk` package provides a Vercel AI SDK-compatible tool that enables AI agents to execute Playwright code on Kernel remote browsers. This tool integrates seamlessly with:

* **Vercel AI SDK’s `generateText()`** - For direct LLM-powered browser automation
* **Vercel AI SDK’s `Agent()` class** - For building autonomous browser automation agents

With this tool, you can build AI-powered applications that browse the web, extract data, interact with websites, and perform complex automation tasks—all through natural language instructions. [Learn more about the AI SDK tool →](https://www.kernel.sh/docs/integrations/vercel/ai-sdk)

### [​](#vercel-marketplace-integration)Vercel Marketplace Integration

The [Vercel Marketplace integration](https://www.kernel.sh/docs/integrations/vercel/marketplace) allows you to install and configure Kernel directly from the Vercel dashboard. This integration:

* Automatically provisions a Kernel Organization and API key
* Syncs your `KERNEL_API_KEY` to your Vercel project’s environment variables
* Manages billing directly through Vercel
* Syncs team members and roles between Vercel and Kernel

[Learn more about the Marketplace integration →](https://www.kernel.sh/docs/integrations/vercel/marketplace)

## [​](#use-cases)Use Cases

* **Automated Testing** - Build AI-powered test automation
* **Web Monitoring** - Monitor websites for changes or specific content
* **Data Extraction** - Extract data from websites using natural language
* **Form Automation** - Automate form submissions and data entry

## [​](#next-steps)Next Steps

----
url: https://www.kernel.sh/docs/api-reference/browsers/get-the-current-mouse-cursor-position-on-the-browser-instance
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.computer.getMousePosition('id');

console.log(response.x);
```

```
{
  "x": 123,
  "y": 123
}
```

get\_mouse\_position

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.computer.getMousePosition('id');

console.log(response.x);
```

```
{
  "x": 123,
  "y": 123
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Response

Current mouse position

[​](#response-x)

x

integer

required

X coordinate of the cursor

[​](#response-y)

y

integer

required

Y coordinate of the cursor

[Execute a batch of computer actions sequentially](https://www.kernel.sh/docs/api-reference/browsers/execute-a-batch-of-computer-actions-sequentially)

[Previous](https://www.kernel.sh/docs/api-reference/browsers/execute-a-batch-of-computer-actions-sequentially)

[List browser session replays](https://www.kernel.sh/docs/api-reference/browser-replays/list-browser-session-replays)

[Next](https://www.kernel.sh/docs/api-reference/browser-replays/list-browser-session-replays)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/create-a-new-directory
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.createDirectory('id', { path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

create\_directory

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.createDirectory('id', { path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-path)

path

string

required

Absolute directory path to create.

Pattern: `^/.*`

[​](#body-mode)

mode

string

Optional directory mode (octal string, e.g. 755). Defaults to 755.

Pattern: `^[0-7]{3,4}$`

#### Response

Directory created successfully

[List files in a directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/list-files-in-a-directory)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/list-files-in-a-directory)

[Delete a file](https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-file)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-file)

⌘I

----
url: https://www.kernel.sh/docs/proxies/datacenter
----

Datacenter proxies use IP addresses assigned from datacenter servers to route your traffic and access locations around the world. With a shorter journey and simplified architecture, datacenter proxies are both the fastest and most cost-effective proxy option.

## [​](#configuration)Configuration

Datacenter proxies require a country to route traffic through:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const proxy = await kernel.proxies.create({
  type: 'datacenter',
  name: 'my-us-datacenter',
  config: {
    country: 'US',
  },
});

const browser = await kernel.browsers.create({
  proxy_id: proxy.id,
});
```

## [​](#configuration-parameters)Configuration Parameters

* **`country`** (optional) - ISO 3166 country code (e.g., `US`, `GB`, `FR`) or `EU` for European Union exit nodes
* **`bypass_hosts`** (optional) - Array of hostnames that bypass the proxy and connect directly (max 100 entries)

## [​](#bypass-hosts)Bypass hosts

Configure specific hostnames to bypass the proxy:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const proxy = await kernel.proxies.create({
  type: 'datacenter',
  name: 'datacenter-with-bypass',
  config: {
    country: 'US',
  },
  bypass_hosts: [
    'localhost',
    'internal.service.local',
    '*.amazonaws.com',
  ],
});
```

Bypass hosts support exact hostnames and wildcard subdomains (`*.example.com`). See the [overview](https://www.kernel.sh/docs/proxies/overview#bypass-hosts) for full details.

----
url: https://www.kernel.sh/docs/proxies/residential
----

Residential proxies route traffic through real residential IP addresses. They support advanced targeting options including city, state, and operating system.

## [​](#configuration)Configuration

Create a residential proxy with a target country:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const proxy = await kernel.proxies.create({
  type: 'residential',
  name: 'my-us-residential',
  config: {
    country: 'US'
  }
});

const browser = await kernel.browsers.create({
  proxy_id: proxy.id,
});
```

## [​](#configuration-parameters)Configuration Parameters

* **`country`** - ISO 3166 country code. Must be provided when providing other targeting options.
* **`state`** - Two-letter state code. Only supported for US.
* **`city`** - City name (lowercase, no spaces, e.g., `sanfrancisco`, `newyork`).
* **`zip`** - US ZIP code (5 digits). Can only be used with `country` set to `US`. Cannot be combined with `city` or `state`.
* **`asn`** - Autonomous System Number. Conflicts with city and state.
* **`bypass_hosts`** (optional) - Array of hostnames that bypass the proxy and connect directly (max 100 entries)

## [​](#advanced-targeting-examples)Advanced Targeting Examples

Kernel recommends using the least-specific targeting configuration that works for your use case. The more specific a configuration, the less available IPs there are, increasing the chance of a slow connection or no available connection (`no_peer` connection error).

### [​](#target-by-city)Target by City

Route traffic through a specific city:

```
const proxy = await kernel.proxies.create({
  type: 'residential',
  name: 'la-residential',
  config: {
    country: 'US',
    state: 'CA',
    city: 'los_angeles'
  }
});
```

If the city name is not matched, the API will return the best 10 city names from the state to help you find the correct city identifier.

### [​](#target-by-state)Target by State

Route traffic through a specific state:

```
const proxy = await kernel.proxies.create({
  type: 'residential',
  name: 'ny-residential',
  config: {
    country: 'US',
    state: 'NY'
  }
});
```

If the state name is not matched, the API will return the most-available 10 states.

### [​](#target-by-asn)Target by ASN

Route traffic through a specific Autonomous System Number (ISP):

```
const proxy = await kernel.proxies.create({
  type: 'residential',
  name: 'comcast-residential',
  config: {
    country: 'US',
    asn: 'AS7922'
  }
});
```

If the ASN is not matched, the API will return the most-available 10 examples.

### [​](#target-by-zip-code)Target by ZIP code

Route traffic through a specific US ZIP code area:

```
const proxy = await kernel.proxies.create({
  type: 'residential',
  name: 'nyc-residential',
  config: {
    country: 'US',
    zip: '10001'
  }
});
```

ZIP code targeting is US-only and cannot be combined with `state` or `city`. The exit IP will be in the geographic area of the requested ZIP code, but the IP’s exact ZIP may differ slightly (e.g., requesting `90210` may route through `90401` in the same metro area).

Not all ZIP codes have available residential IPs. If a ZIP code is unavailable, proxy creation will fail with a message suggesting alternatives: a nearby ZIP, city/state targeting, or country-only targeting.

## [​](#bypass-hosts)Bypass hosts

Configure specific hostnames to bypass the proxy and connect directly:

```
const proxy = await kernel.proxies.create({
  type: 'residential',
  name: 'residential-with-bypass',
  config: {
    country: 'US',
  },
  bypass_hosts: [
    'localhost',
    'metadata.google.internal',
    '*.internal.company.com',
  ],
});
```

See the [overview](https://www.kernel.sh/docs/proxies/overview#bypass-hosts) for full bypass host rules and examples.

----
url: https://www.kernel.sh/docs/community/github
----

[Skip to content](https://github.com/kernel/kernel-images#start-of-content)

You signed in with another tab or window. [Reload](https://github.com/kernel/kernel-images) to refresh your session.You signed out in another tab or window. [Reload](https://github.com/kernel/kernel-images) to refresh your session.You switched accounts on another tab or window. [Reload](https://github.com/kernel/kernel-images) to refresh your session.Dismiss alert

{{ message }}

[kernel](https://github.com/kernel)/ **[kernel-images](https://github.com/kernel/kernel-images)** Public

- [Notifications](https://github.com/login?return_to=%2Fkernel%2Fkernel-images) You must be signed in to change notification settings
- [Fork\\
45](https://github.com/login?return_to=%2Fkernel%2Fkernel-images)
- [Star\\
728](https://github.com/login?return_to=%2Fkernel%2Fkernel-images)


main

[**44** Branches](https://github.com/kernel/kernel-images/branches) [**0** Tags](https://github.com/kernel/kernel-images/tags)

[Go to Branches page](https://github.com/kernel/kernel-images/branches)[Go to Tags page](https://github.com/kernel/kernel-images/tags)

Go to file

Code

Open more actions menu

## Folders and files

| Name | Name | Last commit message | Last commit date |
| --- | --- | --- | --- |
| ## Latest commit<br>[![sjmiller609](https://avatars.githubusercontent.com/u/7516283?v=4&size=40)](https://github.com/sjmiller609)[sjmiller609](https://github.com/kernel/kernel-images/commits?author=sjmiller609)<br>[Set Chromium MaxConnectionsPerProxy default to 16 (](https://github.com/kernel/kernel-images/commit/582ab6f62932650adf6369adfc5a13d7384349a3) [#183](https://github.com/kernel/kernel-images/pull/183) [)](https://github.com/kernel/kernel-images/commit/582ab6f62932650adf6369adfc5a13d7384349a3)<br>Open commit detailssuccess<br>4 days agoMar 19, 2026<br>[582ab6f](https://github.com/kernel/kernel-images/commit/582ab6f62932650adf6369adfc5a13d7384349a3) · 4 days agoMar 19, 2026<br>## History<br>[124 Commits](https://github.com/kernel/kernel-images/commits/main/) <br>Open commit details<br>[View commit history for this file.](https://github.com/kernel/kernel-images/commits/main/) 124 Commits |
| [.devcontainer](https://github.com/kernel/kernel-images/tree/main/.devcontainer ".devcontainer") | [.devcontainer](https://github.com/kernel/kernel-images/tree/main/.devcontainer ".devcontainer") | [Add devcontainer configuration for development (](https://github.com/kernel/kernel-images/commit/a0dca701e3c006fbc2961e72825f757a09bc6708 "Add devcontainer configuration for development (#65)  This PR adds a devcontainer configuration that forwards common ports used during development including those for WebRTC. Installation of kraftkit and updating/upgrading occur on container creation using the `onCreateCommand` key. The latest Ubuntu LTS is used in an attempt to maintain some parity with the build pipeline.   <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > Add VS Code devcontainer based on Ubuntu with Docker-in-Docker, Go/Node features, kraftkit install on create, and forwarded TCP/UDP ports (incl. WebRTC). >  > - **Dev Environment**: >   - **New `/.devcontainer/devcontainer.json`**: > - Base image `mcr.microsoft.com/devcontainers/base:ubuntu` with features: Docker-in-Docker, Go, Node (latest). > - `onCreateCommand`: apt setup, add Unikraft repo, install `kraftkit`, system upgrade. > - Forward ports: `444` (Kernel Images API), `8080` (Web Interface), `9222` (CDP); UDP range `56000-56100` for WebRTC. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d028f0e192938bad8983bd48b6527977425a87d2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->  ---  <!-- mesa-description-start --> ## TL;DR  Adds a devcontainer configuration to standardize the development environment.  ## Why we made these changes  To create a consistent development environment that mirrors the build pipeline, simplifies onboarding, and automates the installation of necessary tools like `kraftkit`.  ## What changed?  - Added `.devcontainer/devcontainer.json` to define the development environment. - The container is based on Ubuntu LTS and includes features for Docker-in-Docker, Go, and Node.js. - Uses `onCreateCommand` to automatically install `kraftkit` and run system updates on container creation. - Forwards TCP ports `444` (API), `8080` (Web), `9222` (CDP), and the UDP port range `56000-56100` for WebRTC.  ## Validation  - [ ] Devcontainer builds and starts successfully. - [ ] `kraftkit` is installed and available in the container's terminal. - [ ] Forwarded ports are accessible from the host machine.  <sup>_Description generated by Mesa. [Update settings](https://app.mesa.dev/onkernel/settings/pull-requests)_</sup> <!-- mesa-description-end -->") [#65](https://github.com/kernel/kernel-images/pull/65) [)](https://github.com/kernel/kernel-images/commit/a0dca701e3c006fbc2961e72825f757a09bc6708 "Add devcontainer configuration for development (#65)  This PR adds a devcontainer configuration that forwards common ports used during development including those for WebRTC. Installation of kraftkit and updating/upgrading occur on container creation using the `onCreateCommand` key. The latest Ubuntu LTS is used in an attempt to maintain some parity with the build pipeline.   <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > Add VS Code devcontainer based on Ubuntu with Docker-in-Docker, Go/Node features, kraftkit install on create, and forwarded TCP/UDP ports (incl. WebRTC). >  > - **Dev Environment**: >   - **New `/.devcontainer/devcontainer.json`**: > - Base image `mcr.microsoft.com/devcontainers/base:ubuntu` with features: Docker-in-Docker, Go, Node (latest). > - `onCreateCommand`: apt setup, add Unikraft repo, install `kraftkit`, system upgrade. > - Forward ports: `444` (Kernel Images API), `8080` (Web Interface), `9222` (CDP); UDP range `56000-56100` for WebRTC. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d028f0e192938bad8983bd48b6527977425a87d2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->  ---  <!-- mesa-description-start --> ## TL;DR  Adds a devcontainer configuration to standardize the development environment.  ## Why we made these changes  To create a consistent development environment that mirrors the build pipeline, simplifies onboarding, and automates the installation of necessary tools like `kraftkit`.  ## What changed?  - Added `.devcontainer/devcontainer.json` to define the development environment. - The container is based on Ubuntu LTS and includes features for Docker-in-Docker, Go, and Node.js. - Uses `onCreateCommand` to automatically install `kraftkit` and run system updates on container creation. - Forwards TCP ports `444` (API), `8080` (Web), `9222` (CDP), and the UDP port range `56000-56100` for WebRTC.  ## Validation  - [ ] Devcontainer builds and starts successfully. - [ ] `kraftkit` is installed and available in the container's terminal. - [ ] Forwarded ports are accessible from the host machine.  <sup>_Description generated by Mesa. [Update settings](https://app.mesa.dev/onkernel/settings/pull-requests)_</sup> <!-- mesa-description-end -->") | 5 months agoOct 30, 2025 |
| [.github](https://github.com/kernel/kernel-images/tree/main/.github ".github") | [.github](https://github.com/kernel/kernel-images/tree/main/.github ".github") | [feat: improve e2e test infrastructure (](https://github.com/kernel/kernel-images/commit/12b2f2835fbf2855d5990d13c08b4eea19626eae "feat: improve e2e test infrastructure (#132)  ## Summary  This PR contributes improvements to the e2e test infrastructure:  ### Test Infrastructure Improvements  - **`ContainerOptions` struct** - Adds `HostAccess` option for tests that need `--add-host=host.docker.internal:host-gateway` to reach services on the host machine - **`runContainerWithOptions()`** - New function supporting `ContainerOptions` for flexible container configuration - **`getContainerLogs()`** - New helper to retrieve the last N lines of container logs for debugging failed tests - **`waitHTTPOrExitWithLogs()`** - Enhanced wait function that:   - Captures container logs on failure for easier debugging - Periodically logs container status during the wait for better visibility in CI - **`--no-sandbox` auto-injection** - Automatically adds `--no-sandbox` to `CHROMIUM_FLAGS` for CI environments where unprivileged user namespaces may be disabled (e.g., Ubuntu 24.04 GitHub Actions) - **`--tmpfs` mode fix** - Changed from `:size=2g` to `:size=2g,mode=1777` for proper `/dev/shm` permissions - **Sequential test execution** - Added `-p 1` flag to run tests sequentially, avoiding port conflicts since all e2e tests bind to the same ports (10001, 9222)  ## Test plan  - [ ] CI passes with all e2e tests - [ ] Verify tests run sequentially without port conflicts - [ ] Verify container logs are captured on test failure") [#132](https://github.com/kernel/kernel-images/pull/132) [)](https://github.com/kernel/kernel-images/commit/12b2f2835fbf2855d5990d13c08b4eea19626eae "feat: improve e2e test infrastructure (#132)  ## Summary  This PR contributes improvements to the e2e test infrastructure:  ### Test Infrastructure Improvements  - **`ContainerOptions` struct** - Adds `HostAccess` option for tests that need `--add-host=host.docker.internal:host-gateway` to reach services on the host machine - **`runContainerWithOptions()`** - New function supporting `ContainerOptions` for flexible container configuration - **`getContainerLogs()`** - New helper to retrieve the last N lines of container logs for debugging failed tests - **`waitHTTPOrExitWithLogs()`** - Enhanced wait function that:   - Captures container logs on failure for easier debugging - Periodically logs container status during the wait for better visibility in CI - **`--no-sandbox` auto-injection** - Automatically adds `--no-sandbox` to `CHROMIUM_FLAGS` for CI environments where unprivileged user namespaces may be disabled (e.g., Ubuntu 24.04 GitHub Actions) - **`--tmpfs` mode fix** - Changed from `:size=2g` to `:size=2g,mode=1777` for proper `/dev/shm` permissions - **Sequential test execution** - Added `-p 1` flag to run tests sequentially, avoiding port conflicts since all e2e tests bind to the same ports (10001, 9222)  ## Test plan  - [ ] CI passes with all e2e tests - [ ] Verify tests run sequentially without port conflicts - [ ] Verify container logs are captured on test failure") | 2 months agoJan 26, 2026 |
| [images](https://github.com/kernel/kernel-images/tree/main/images "images") | [images](https://github.com/kernel/kernel-images/tree/main/images "images") | [fix: update live view logo and favicon to latest Kernel branding (](https://github.com/kernel/kernel-images/commit/11c57ac711aea433e61340e2bd86e261c4c84b32 "fix: update live view logo and favicon to latest Kernel branding (#181)  ## Summary  - Replace the old purple flower logo (`#AC86F9`) with the current green \"knl\" Kernel logo (`#81B300`) in the live view client - Update `logo.svg` used on the loading screen (`connect.vue`) and about page (`about.vue`) - Add inline SVG favicon via base64 data URI in `index.html` — the previous PNG favicon references (`favicon-32x32.png`, `favicon-16x16.png`) have been removed from `index.html` and the old PNG files deleted from `public/` - Update theme colors in `site.webmanifest` and `browserconfig.xml` from `#19bd9c` to `#81B300`  > **Note:** `kernel-images-private` has the same old logo and should get the same update.  ## Test plan  - [ ] Build the chromium-headful image and verify the loading screen shows the new green \"knl\" logo - [ ] Open a live view URL and confirm the browser tab favicon shows the new Kernel icon - [ ] Verify no visual regressions on the connect/about pages  <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Low Risk** > Low risk: static asset and metadata updates only (logo SVG, favicon link, and theme colors) with no runtime logic changes. >  > **Overview** > Updates the chromium-headful live view client to the latest Kernel branding by replacing the existing `logo.svg` with the new green “knl” mark. >  > Switches the favicon setup in `public/index.html` from missing PNG/icon references to an inline base64 SVG favicon, and updates PWA/Windows tile colors in `site.webmanifest` and `browserconfig.xml` to `#81B300`. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit aa365f6590b658ae7336168f5bac242afd1e6c42. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") [#181](https://github.com/kernel/kernel-images/pull/181) [)](https://github.com/kernel/kernel-images/commit/11c57ac711aea433e61340e2bd86e261c4c84b32 "fix: update live view logo and favicon to latest Kernel branding (#181)  ## Summary  - Replace the old purple flower logo (`#AC86F9`) with the current green \"knl\" Kernel logo (`#81B300`) in the live view client - Update `logo.svg` used on the loading screen (`connect.vue`) and about page (`about.vue`) - Add inline SVG favicon via base64 data URI in `index.html` — the previous PNG favicon references (`favicon-32x32.png`, `favicon-16x16.png`) have been removed from `index.html` and the old PNG files deleted from `public/` - Update theme colors in `site.webmanifest` and `browserconfig.xml` from `#19bd9c` to `#81B300`  > **Note:** `kernel-images-private` has the same old logo and should get the same update.  ## Test plan  - [ ] Build the chromium-headful image and verify the loading screen shows the new green \"knl\" logo - [ ] Open a live view URL and confirm the browser tab favicon shows the new Kernel icon - [ ] Verify no visual regressions on the connect/about pages  <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Low Risk** > Low risk: static asset and metadata updates only (logo SVG, favicon link, and theme colors) with no runtime logic changes. >  > **Overview** > Updates the chromium-headful live view client to the latest Kernel branding by replacing the existing `logo.svg` with the new green “knl” mark. >  > Switches the favicon setup in `public/index.html` from missing PNG/icon references to an inline base64 SVG favicon, and updates PWA/Windows tile colors in `site.webmanifest` and `browserconfig.xml` to `#81B300`. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit aa365f6590b658ae7336168f5bac242afd1e6c42. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") | last weekMar 17, 2026 |
| [plans](https://github.com/kernel/kernel-images/tree/main/plans "plans") | [plans](https://github.com/kernel/kernel-images/tree/main/plans "plans") | [feat: migrate TTY attach from HTTP hijack to WebSocket (](https://github.com/kernel/kernel-images/commit/0910873f2f52b1b689ee6d4a065e3ace0db3494c "feat: migrate TTY attach from HTTP hijack to WebSocket (#114)  ## Summary  - Replace HTTP connection hijacking for PTY attach with WebSocket-based protocol - Improves compatibility with load balancers, reverse proxies, and API gateways - Add plan document describing the migration and protocol design  ## Background  The previous HTTP hijack approach for `/process/{process_id}/attach` doesn't work well when there are multiple layers of proxying in front of this image. WebSockets provide a more robust solution for bidirectional streaming that is well-understood by intermediary infrastructure.  ## Protocol  The new WebSocket attach protocol:  | Direction | Message Type | Content | |-----------|--------------|---------| | Client → Server | Binary | Raw bytes for PTY stdin | | Server → Client | Binary | Raw bytes from PTY stdout | | Client → Server | Text (JSON) | Control messages like `{\"type\": \"resize\", \"rows\": 24, \"cols\": 80}` | | Server → Client | Text (JSON) | Events like `{\"type\": \"exit\", \"exitCode\": 0}` |  ## Changes  - `server/cmd/api/api/process.go`: Add `HandleProcessAttachWS` WebSocket handler - `server/cmd/api/main.go`: Route attach endpoint to new WebSocket handler - `plans/migrate-tty-attach-to-websocket.md`: Design document  ## Test plan  - [x] All unit tests pass - [ ] Manual testing with WebSocket client - [ ] Test through proxy to verify WebSocket works with intermediaries  # Checklist  - [ ] A link to a related issue in our repository - [x] A description of the changes proposed in the pull request. - [ ] @mentions of the person or team responsible for reviewing proposed changes.  <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > Implements a WebSocket-based PTY attach that is proxy-friendly and supports control framing. >  > - Adds `HandleProcessAttachWS` using `github.com/coder/websocket`; streams stdin/stdout as binary and handles JSON control (`resize`, `exit`, `error`) > - Serializes WS writes, coordinates graceful shutdown across PTY/WS/process, and emits exit code before close > - Routes `GET /process/{process_id}/attach` to the new WS handler in `main.go` (legacy hijack handler no longer routed) > - Introduces `server/lib/ptyio` with `AttachControlMessage`, message type enums, constants, and `ReadPTYToWriter` (poll-based PTY reader) > - Returns JSON errors when attach fails (not found, not PTY, conflict) >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit a185e481af50362379833e50a0e44fe196ddd20c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") [#114](https://github.com/kernel/kernel-images/pull/114) [)](https://github.com/kernel/kernel-images/commit/0910873f2f52b1b689ee6d4a065e3ace0db3494c "feat: migrate TTY attach from HTTP hijack to WebSocket (#114)  ## Summary  - Replace HTTP connection hijacking for PTY attach with WebSocket-based protocol - Improves compatibility with load balancers, reverse proxies, and API gateways - Add plan document describing the migration and protocol design  ## Background  The previous HTTP hijack approach for `/process/{process_id}/attach` doesn't work well when there are multiple layers of proxying in front of this image. WebSockets provide a more robust solution for bidirectional streaming that is well-understood by intermediary infrastructure.  ## Protocol  The new WebSocket attach protocol:  | Direction | Message Type | Content | |-----------|--------------|---------| | Client → Server | Binary | Raw bytes for PTY stdin | | Server → Client | Binary | Raw bytes from PTY stdout | | Client → Server | Text (JSON) | Control messages like `{\"type\": \"resize\", \"rows\": 24, \"cols\": 80}` | | Server → Client | Text (JSON) | Events like `{\"type\": \"exit\", \"exitCode\": 0}` |  ## Changes  - `server/cmd/api/api/process.go`: Add `HandleProcessAttachWS` WebSocket handler - `server/cmd/api/main.go`: Route attach endpoint to new WebSocket handler - `plans/migrate-tty-attach-to-websocket.md`: Design document  ## Test plan  - [x] All unit tests pass - [ ] Manual testing with WebSocket client - [ ] Test through proxy to verify WebSocket works with intermediaries  # Checklist  - [ ] A link to a related issue in our repository - [x] A description of the changes proposed in the pull request. - [ ] @mentions of the person or team responsible for reviewing proposed changes.  <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > Implements a WebSocket-based PTY attach that is proxy-friendly and supports control framing. >  > - Adds `HandleProcessAttachWS` using `github.com/coder/websocket`; streams stdin/stdout as binary and handles JSON control (`resize`, `exit`, `error`) > - Serializes WS writes, coordinates graceful shutdown across PTY/WS/process, and emits exit code before close > - Routes `GET /process/{process_id}/attach` to the new WS handler in `main.go` (legacy hijack handler no longer routed) > - Introduces `server/lib/ptyio` with `AttachControlMessage`, message type enums, constants, and `ReadPTYToWriter` (poll-based PTY reader) > - Returns JSON errors when attach fails (not found, not PTY, conflict) >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit a185e481af50362379833e50a0e44fe196ddd20c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") | 2 months agoJan 12, 2026 |
| [server](https://github.com/kernel/kernel-images/tree/main/server "server") | [server](https://github.com/kernel/kernel-images/tree/main/server "server") | [Set Chromium MaxConnectionsPerProxy default to 16 (](https://github.com/kernel/kernel-images/commit/582ab6f62932650adf6369adfc5a13d7384349a3 "Set Chromium MaxConnectionsPerProxy default to 16 (#183)  **Summary**  Set Chromium’s default managed policy `MaxConnectionsPerProxy` to `16` in the `kernel-images` browser images.  **Why**  In live testing on a stealth Envoy VM with a 6-tab workload, Chromium’s default behavior allowed substantially higher upstream proxy fanout than desired. Setting `MaxConnectionsPerProxy` effectively clamps Chrome-to-proxy and proxy-to-origin connection counts much closer to the configured limit.  Observed results from the same workload: - Default: peak ~34 Chrome->Envoy connections, ~33 Envoy->Ping connections - `MaxConnectionsPerProxy=16`: peak ~17 / ~17 - `MaxConnectionsPerProxy=8`: peak ~9 / ~9 - `MaxConnectionsPerProxy=4`: peak ~7 / ~7  This makes `16` a good default for reducing proxy connection fanout without needing per-session configuration.  **What changed**  - Added `\"MaxConnectionsPerProxy\": 16` to the shared managed Chromium policy baked into the browser images. - Added assertions in existing e2e tests that read `/etc/chromium/policies/managed/policy.json` to verify the default is present.  **Implementation details**  The default policy is sourced from the shared image policy file and copied into the VM at `/etc/chromium/policies/managed/policy.json`, so this change applies to the browser image startup path directly.  **Validation**  - Confirmed the managed policy JSON contains `MaxConnectionsPerProxy: 16` - Ran:   - `go test ./lib/policy`   - `go test -run '^$' ./e2e`   <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Medium Risk** > Changes a Chromium managed policy that can affect browser networking/concurrency behavior across all images. Added e2e checks reduce regression risk but policy changes may have wide runtime impact. >  > **Overview** > **Updates the default managed Chromium policy** to set `MaxConnectionsPerProxy` to `16` in `shared/chromium-policies/managed/policy.json`. >  > **Hardens e2e coverage** by asserting `MaxConnectionsPerProxy` exists and equals `16` in both the Chromium policy test and the enterprise extension policy test, so missing/changed policy values are caught early. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 524dd6b7ded540d22e19210e52a9badff0c42f5a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") [#183](https://github.com/kernel/kernel-images/pull/183) [)](https://github.com/kernel/kernel-images/commit/582ab6f62932650adf6369adfc5a13d7384349a3 "Set Chromium MaxConnectionsPerProxy default to 16 (#183)  **Summary**  Set Chromium’s default managed policy `MaxConnectionsPerProxy` to `16` in the `kernel-images` browser images.  **Why**  In live testing on a stealth Envoy VM with a 6-tab workload, Chromium’s default behavior allowed substantially higher upstream proxy fanout than desired. Setting `MaxConnectionsPerProxy` effectively clamps Chrome-to-proxy and proxy-to-origin connection counts much closer to the configured limit.  Observed results from the same workload: - Default: peak ~34 Chrome->Envoy connections, ~33 Envoy->Ping connections - `MaxConnectionsPerProxy=16`: peak ~17 / ~17 - `MaxConnectionsPerProxy=8`: peak ~9 / ~9 - `MaxConnectionsPerProxy=4`: peak ~7 / ~7  This makes `16` a good default for reducing proxy connection fanout without needing per-session configuration.  **What changed**  - Added `\"MaxConnectionsPerProxy\": 16` to the shared managed Chromium policy baked into the browser images. - Added assertions in existing e2e tests that read `/etc/chromium/policies/managed/policy.json` to verify the default is present.  **Implementation details**  The default policy is sourced from the shared image policy file and copied into the VM at `/etc/chromium/policies/managed/policy.json`, so this change applies to the browser image startup path directly.  **Validation**  - Confirmed the managed policy JSON contains `MaxConnectionsPerProxy: 16` - Ran:   - `go test ./lib/policy`   - `go test -run '^$' ./e2e`   <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Medium Risk** > Changes a Chromium managed policy that can affect browser networking/concurrency behavior across all images. Added e2e checks reduce regression risk but policy changes may have wide runtime impact. >  > **Overview** > **Updates the default managed Chromium policy** to set `MaxConnectionsPerProxy` to `16` in `shared/chromium-policies/managed/policy.json`. >  > **Hardens e2e coverage** by asserting `MaxConnectionsPerProxy` exists and equals `16` in both the Chromium policy test and the enterprise extension policy test, so missing/changed policy values are caught early. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 524dd6b7ded540d22e19210e52a9badff0c42f5a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") | 4 days agoMar 19, 2026 |
| [shared](https://github.com/kernel/kernel-images/tree/main/shared "shared") | [shared](https://github.com/kernel/kernel-images/tree/main/shared "shared") | [Set Chromium MaxConnectionsPerProxy default to 16 (](https://github.com/kernel/kernel-images/commit/582ab6f62932650adf6369adfc5a13d7384349a3 "Set Chromium MaxConnectionsPerProxy default to 16 (#183)  **Summary**  Set Chromium’s default managed policy `MaxConnectionsPerProxy` to `16` in the `kernel-images` browser images.  **Why**  In live testing on a stealth Envoy VM with a 6-tab workload, Chromium’s default behavior allowed substantially higher upstream proxy fanout than desired. Setting `MaxConnectionsPerProxy` effectively clamps Chrome-to-proxy and proxy-to-origin connection counts much closer to the configured limit.  Observed results from the same workload: - Default: peak ~34 Chrome->Envoy connections, ~33 Envoy->Ping connections - `MaxConnectionsPerProxy=16`: peak ~17 / ~17 - `MaxConnectionsPerProxy=8`: peak ~9 / ~9 - `MaxConnectionsPerProxy=4`: peak ~7 / ~7  This makes `16` a good default for reducing proxy connection fanout without needing per-session configuration.  **What changed**  - Added `\"MaxConnectionsPerProxy\": 16` to the shared managed Chromium policy baked into the browser images. - Added assertions in existing e2e tests that read `/etc/chromium/policies/managed/policy.json` to verify the default is present.  **Implementation details**  The default policy is sourced from the shared image policy file and copied into the VM at `/etc/chromium/policies/managed/policy.json`, so this change applies to the browser image startup path directly.  **Validation**  - Confirmed the managed policy JSON contains `MaxConnectionsPerProxy: 16` - Ran:   - `go test ./lib/policy`   - `go test -run '^$' ./e2e`   <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Medium Risk** > Changes a Chromium managed policy that can affect browser networking/concurrency behavior across all images. Added e2e checks reduce regression risk but policy changes may have wide runtime impact. >  > **Overview** > **Updates the default managed Chromium policy** to set `MaxConnectionsPerProxy` to `16` in `shared/chromium-policies/managed/policy.json`. >  > **Hardens e2e coverage** by asserting `MaxConnectionsPerProxy` exists and equals `16` in both the Chromium policy test and the enterprise extension policy test, so missing/changed policy values are caught early. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 524dd6b7ded540d22e19210e52a9badff0c42f5a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") [#183](https://github.com/kernel/kernel-images/pull/183) [)](https://github.com/kernel/kernel-images/commit/582ab6f62932650adf6369adfc5a13d7384349a3 "Set Chromium MaxConnectionsPerProxy default to 16 (#183)  **Summary**  Set Chromium’s default managed policy `MaxConnectionsPerProxy` to `16` in the `kernel-images` browser images.  **Why**  In live testing on a stealth Envoy VM with a 6-tab workload, Chromium’s default behavior allowed substantially higher upstream proxy fanout than desired. Setting `MaxConnectionsPerProxy` effectively clamps Chrome-to-proxy and proxy-to-origin connection counts much closer to the configured limit.  Observed results from the same workload: - Default: peak ~34 Chrome->Envoy connections, ~33 Envoy->Ping connections - `MaxConnectionsPerProxy=16`: peak ~17 / ~17 - `MaxConnectionsPerProxy=8`: peak ~9 / ~9 - `MaxConnectionsPerProxy=4`: peak ~7 / ~7  This makes `16` a good default for reducing proxy connection fanout without needing per-session configuration.  **What changed**  - Added `\"MaxConnectionsPerProxy\": 16` to the shared managed Chromium policy baked into the browser images. - Added assertions in existing e2e tests that read `/etc/chromium/policies/managed/policy.json` to verify the default is present.  **Implementation details**  The default policy is sourced from the shared image policy file and copied into the VM at `/etc/chromium/policies/managed/policy.json`, so this change applies to the browser image startup path directly.  **Validation**  - Confirmed the managed policy JSON contains `MaxConnectionsPerProxy: 16` - Ran:   - `go test ./lib/policy`   - `go test -run '^$' ./e2e`   <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Medium Risk** > Changes a Chromium managed policy that can affect browser networking/concurrency behavior across all images. Added e2e checks reduce regression risk but policy changes may have wide runtime impact. >  > **Overview** > **Updates the default managed Chromium policy** to set `MaxConnectionsPerProxy` to `16` in `shared/chromium-policies/managed/policy.json`. >  > **Hardens e2e coverage** by asserting `MaxConnectionsPerProxy` exists and equals `16` in both the Chromium policy test and the enterprise extension policy test, so missing/changed policy values are caught early. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 524dd6b7ded540d22e19210e52a9badff0c42f5a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") | 4 days agoMar 19, 2026 |
| [static/images](https://github.com/kernel/kernel-images/tree/main/static/images "This path skips through empty directories") | [static/images](https://github.com/kernel/kernel-images/tree/main/static/images "This path skips through empty directories") | [update new brand (](https://github.com/kernel/kernel-images/commit/089acbfef6fef8febea186ecaf34f117edd3c79e "update new brand (#160)  <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only updates (email/domain/link changes and a logo asset swap) with no runtime code or security-sensitive logic changes. >  > **Overview** > Updates public-facing project docs to reflect new branding: replaces `oss@onkernel.com` with `oss@kernel.sh` in `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md`, and migrates README links from `onkernel.com` to `kernel.sh`. >  > Swaps the README header logo to `static/images/logo-kernel-light.svg`, removing the old `Kernel-Wordmark_Accent.svg` asset. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 095033d081b418972c7d4fe85f688841dac91a67. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") [#160](https://github.com/kernel/kernel-images/pull/160) [)](https://github.com/kernel/kernel-images/commit/089acbfef6fef8febea186ecaf34f117edd3c79e "update new brand (#160)  <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only updates (email/domain/link changes and a logo asset swap) with no runtime code or security-sensitive logic changes. >  > **Overview** > Updates public-facing project docs to reflect new branding: replaces `oss@onkernel.com` with `oss@kernel.sh` in `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md`, and migrates README links from `onkernel.com` to `kernel.sh`. >  > Swaps the README header logo to `static/images/logo-kernel-light.svg`, removing the old `Kernel-Wordmark_Accent.svg` asset. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 095033d081b418972c7d4fe85f688841dac91a67. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") | last monthFeb 24, 2026 |
| [.dockerignore](https://github.com/kernel/kernel-images/blob/main/.dockerignore ".dockerignore") | [.dockerignore](https://github.com/kernel/kernel-images/blob/main/.dockerignore ".dockerignore") | [save / reuse user data (](https://github.com/kernel/kernel-images/commit/74297556be267393b0ad6cd8584cf4fee555e49e "save / reuse user data (#57)  * begin supervisord-ifying  * supervisord for all headful processes  * multi tail  * better logging  * reorder  * prefix wrapper logs  * headless chromium supervisor setup  * /fs/upload /fs/upload_zip for writing many files  * better logs for headless image  * log tailing, process exec'ing  * rm ncat proxy  * endpoint to download directory as zip  * disable scale to zero on startup for the headless image  * draft e2e test of saving user data  * user profile persistence passing  * cleanup  * ignore *.png  * move server build into Dockerfile  * drop packages: write since we're using dockerhub  * tweak tests  * there will be tests  * use gha docker cache; fix proxy test  * pr feedback  * heartbeat ws client connections") [#57](https://github.com/kernel/kernel-images/pull/57) [)](https://github.com/kernel/kernel-images/commit/74297556be267393b0ad6cd8584cf4fee555e49e "save / reuse user data (#57)  * begin supervisord-ifying  * supervisord for all headful processes  * multi tail  * better logging  * reorder  * prefix wrapper logs  * headless chromium supervisor setup  * /fs/upload /fs/upload_zip for writing many files  * better logs for headless image  * log tailing, process exec'ing  * rm ncat proxy  * endpoint to download directory as zip  * disable scale to zero on startup for the headless image  * draft e2e test of saving user data  * user profile persistence passing  * cleanup  * ignore *.png  * move server build into Dockerfile  * drop packages: write since we're using dockerhub  * tweak tests  * there will be tests  * use gha docker cache; fix proxy test  * pr feedback  * heartbeat ws client connections") | 7 months agoAug 20, 2025 |
| [.gitignore](https://github.com/kernel/kernel-images/blob/main/.gitignore ".gitignore") | [.gitignore](https://github.com/kernel/kernel-images/blob/main/.gitignore ".gitignore") | [feat: add ChromeDriver proxy for WebDriver and BiDi protocol support (](https://github.com/kernel/kernel-images/commit/9816e34659229a970f94e56c677270d394e4698a "feat: add ChromeDriver proxy for WebDriver and BiDi protocol support (#164)  Install ChromeDriver matching the Chromium version in both headful and headless images, managed via supervisord on internal port 9225. A new ChromeDriver proxy (exposed on port 9224) intercepts session creation to inject goog:chromeOptions.debuggerAddress so ChromeDriver attaches to the already-running browser (at port 9222), rewrites webSocketUrl in responses to route BiDi traffic back through the proxy, and transparently proxies all other HTTP and WebSocket traffic.  Extracts the shared WebSocket bidirectional pump logic from devtoolsproxy into a reusable wsproxy package with a MessageTransform hook, used by both the existing DevTools proxy and the new ChromeDriver proxy. Expands CDP discovery endpoint proxying to include /json/list and makes proxy ports configurable via environment variables.  Includes comprehensive unit tests for the ChromeDriver proxy and manual BiDi validation scripts (raw WebSocket, Puppeteer, Selenium).  # Checklist  - [ ] A link to a related issue in our repository - [ ] A description of the changes proposed in the pull request. - [ ] @mentions of the person or team responsible for reviewing proposed changes.   <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Medium Risk** > Introduces a new network-facing ChromeDriver proxy with request/response rewriting and adds new ports/services in the runtime images, which could affect client connectivity and session creation behavior if misconfigured. >  > **Overview** > **Adds ChromeDriver support end-to-end** by installing a matching `chromedriver` into both headful/headless images, running it under supervisord on `127.0.0.1:9225`, and exposing a new external proxy port `9224` (docker + unikernel scripts updated accordingly). >  > **Extends the Go API container** with a new ChromeDriver proxy server that intercepts `POST /session` and BiDi `session.new` to inject `goog:chromeOptions.debuggerAddress` (pointing at the DevTools proxy) and rewrites returned `capabilities.webSocketUrl` so BiDi traffic routes back through the proxy; proxy/DevTools ports and upstream addresses are now configurable via env. >  > **Refactors WebSocket proxying** by extracting shared bidirectional pump logic into `lib/wsproxy` (with an optional message transform hook), migrating the existing DevTools proxy to use it, and improving DevTools discovery proxying to handle `/json/version` and `/json(/list)` with recursive URL rewriting. >  > **Adds test coverage and tooling**: unit tests for URL rewriting + ChromeDriver proxy behavior, new BiDi e2e tests (raw WS + Puppeteer/Selenium/Vibium scripts with npm deps), and minor `.gitignore` updates. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit fd8e1b9412b545e4780a7330c7d28e854ca84927. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->  ---------  Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Rafael Garcia <raf@kernel.sh>") [#…](https://github.com/kernel/kernel-images/pull/164) | 2 weeks agoMar 9, 2026 |
| [AGENTS.md](https://github.com/kernel/kernel-images/blob/main/AGENTS.md "AGENTS.md") | [AGENTS.md](https://github.com/kernel/kernel-images/blob/main/AGENTS.md "AGENTS.md") | [Development environment setup (](https://github.com/kernel/kernel-images/commit/28efa85103a737c0762d30d38ef664b23f2e9362 "Development environment setup (#168)  Update `AGENTS.md` with notes on headful image build time and `/process/exec` API schema.  These additions clarify non-obvious gotchas encountered during development environment setup, specifically regarding the extended build time for the headful image and the expected schema for the `/process/exec` API endpoint.  --- <p><a href=\"https://cursor.com/agents/bc-e841fee2-2b06-4e49-a95d-e72587e8de73\"><picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cursor.com/assets/images/open-in-web-dark.png\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://cursor.com/assets/images/open-in-web-light.png\"><img alt=\"Open in Web\" width=\"114\" height=\"28\" src=\"https://cursor.com/assets/images/open-in-web-dark.png\"></picture></a>&nbsp;<a href=\"https://cursor.com/background-agent?bcId=bc-e841fee2-2b06-4e49-a95d-e72587e8de73\"><picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cursor.com/assets/images/open-in-cursor-dark.png\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://cursor.com/assets/images/open-in-cursor-light.png\"><img alt=\"Open in Cursor\" width=\"131\" height=\"28\" src=\"https://cursor.com/assets/images/open-in-cursor-dark.png\"></picture></a>&nbsp;</p>  <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Low Risk** > Low risk documentation-only change; no runtime code or behavior is modified. >  > **Overview** > Updates `AGENTS.md` with two additional development gotchas: how to build the headful Chromium image (including expected long build time and interactive vs detached run behavior), and a clarification of the `/process/exec` request/response schema (`command` as a string, args in `args`, and base64-encoded `stdout_b64`/`stderr_b64`). >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 7a1ba41bf03dccdea12e9512e6133e7ee65037a8. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->  Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Mason Williams <masnwilliams@users.noreply.github.com>") [#168](https://github.com/kernel/kernel-images/pull/168) [)](https://github.com/kernel/kernel-images/commit/28efa85103a737c0762d30d38ef664b23f2e9362 "Development environment setup (#168)  Update `AGENTS.md` with notes on headful image build time and `/process/exec` API schema.  These additions clarify non-obvious gotchas encountered during development environment setup, specifically regarding the extended build time for the headful image and the expected schema for the `/process/exec` API endpoint.  --- <p><a href=\"https://cursor.com/agents/bc-e841fee2-2b06-4e49-a95d-e72587e8de73\"><picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cursor.com/assets/images/open-in-web-dark.png\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://cursor.com/assets/images/open-in-web-light.png\"><img alt=\"Open in Web\" width=\"114\" height=\"28\" src=\"https://cursor.com/assets/images/open-in-web-dark.png\"></picture></a>&nbsp;<a href=\"https://cursor.com/background-agent?bcId=bc-e841fee2-2b06-4e49-a95d-e72587e8de73\"><picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cursor.com/assets/images/open-in-cursor-dark.png\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://cursor.com/assets/images/open-in-cursor-light.png\"><img alt=\"Open in Cursor\" width=\"131\" height=\"28\" src=\"https://cursor.com/assets/images/open-in-cursor-dark.png\"></picture></a>&nbsp;</p>  <!-- CURSOR_SUMMARY --> ---  > [!NOTE] > **Low Risk** > Low risk documentation-only change; no runtime code or behavior is modified. >  > **Overview** > Updates `AGENTS.md` with two additional development gotchas: how to build the headful Chromium image (including expected long build time and interactive vs detached run behavior), and a clarification of the `/process/exec` request/response schema (`command` as a string, args in `args`, and base64-encoded `stdout_b64`/`stderr_b64`). >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 7a1ba41bf03dccdea12e9512e6133e7ee65037a8. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->  Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Mason Williams <masnwilliams@users.noreply.github.com>") | 3 weeks agoFeb 27, 2026 |
| [CODE\_OF\_CONDUCT.md](https://github.com/kernel/kernel-images/blob/main/CODE_OF_CONDUCT.md "CODE_OF_CONDUCT.md") | [CODE\_OF\_CONDUCT.md](https://github.com/kernel/kernel-images/blob/main/CODE_OF_CONDUCT.md "CODE_OF_CONDUCT.md") | [update new brand (](https://github.com/kernel/kernel-images/commit/089acbfef6fef8febea186ecaf34f117edd3c79e "update new brand (#160)  <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only updates (email/domain/link changes and a logo asset swap) with no runtime code or security-sensitive logic changes. >  > **Overview** > Updates public-facing project docs to reflect new branding: replaces `oss@onkernel.com` with `oss@kernel.sh` in `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md`, and migrates README links from `onkernel.com` to `kernel.sh`. >  > Swaps the README header logo to `static/images/logo-kernel-light.svg`, removing the old `Kernel-Wordmark_Accent.svg` asset. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 095033d081b418972c7d4fe85f688841dac91a67. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") [#160](https://github.com/kernel/kernel-images/pull/160) [)](https://github.com/kernel/kernel-images/commit/089acbfef6fef8febea186ecaf34f117edd3c79e "update new brand (#160)  <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only updates (email/domain/link changes and a logo asset swap) with no runtime code or security-sensitive logic changes. >  > **Overview** > Updates public-facing project docs to reflect new branding: replaces `oss@onkernel.com` with `oss@kernel.sh` in `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md`, and migrates README links from `onkernel.com` to `kernel.sh`. >  > Swaps the README header logo to `static/images/logo-kernel-light.svg`, removing the old `Kernel-Wordmark_Accent.svg` asset. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 095033d081b418972c7d4fe85f688841dac91a67. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") | last monthFeb 24, 2026 |
| [CONTRIBUTING.md](https://github.com/kernel/kernel-images/blob/main/CONTRIBUTING.md "CONTRIBUTING.md") | [CONTRIBUTING.md](https://github.com/kernel/kernel-images/blob/main/CONTRIBUTING.md "CONTRIBUTING.md") | [update new brand (](https://github.com/kernel/kernel-images/commit/089acbfef6fef8febea186ecaf34f117edd3c79e "update new brand (#160)  <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only updates (email/domain/link changes and a logo asset swap) with no runtime code or security-sensitive logic changes. >  > **Overview** > Updates public-facing project docs to reflect new branding: replaces `oss@onkernel.com` with `oss@kernel.sh` in `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md`, and migrates README links from `onkernel.com` to `kernel.sh`. >  > Swaps the README header logo to `static/images/logo-kernel-light.svg`, removing the old `Kernel-Wordmark_Accent.svg` asset. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 095033d081b418972c7d4fe85f688841dac91a67. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") [#160](https://github.com/kernel/kernel-images/pull/160) [)](https://github.com/kernel/kernel-images/commit/089acbfef6fef8febea186ecaf34f117edd3c79e "update new brand (#160)  <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only updates (email/domain/link changes and a logo asset swap) with no runtime code or security-sensitive logic changes. >  > **Overview** > Updates public-facing project docs to reflect new branding: replaces `oss@onkernel.com` with `oss@kernel.sh` in `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md`, and migrates README links from `onkernel.com` to `kernel.sh`. >  > Swaps the README header logo to `static/images/logo-kernel-light.svg`, removing the old `Kernel-Wordmark_Accent.svg` asset. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 095033d081b418972c7d4fe85f688841dac91a67. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") | last monthFeb 24, 2026 |
| [LICENSE](https://github.com/kernel/kernel-images/blob/main/LICENSE "LICENSE") | [LICENSE](https://github.com/kernel/kernel-images/blob/main/LICENSE "LICENSE") | [Open source release of Kernel](https://github.com/kernel/kernel-images/commit/55eaf7bb4621a30e569a0e5b8538b1686fb1f263 "Open source release of Kernel") | 11 months agoApr 11, 2025 |
| [README.md](https://github.com/kernel/kernel-images/blob/main/README.md "README.md") | [README.md](https://github.com/kernel/kernel-images/blob/main/README.md "README.md") | [update new brand (](https://github.com/kernel/kernel-images/commit/089acbfef6fef8febea186ecaf34f117edd3c79e "update new brand (#160)  <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only updates (email/domain/link changes and a logo asset swap) with no runtime code or security-sensitive logic changes. >  > **Overview** > Updates public-facing project docs to reflect new branding: replaces `oss@onkernel.com` with `oss@kernel.sh` in `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md`, and migrates README links from `onkernel.com` to `kernel.sh`. >  > Swaps the README header logo to `static/images/logo-kernel-light.svg`, removing the old `Kernel-Wordmark_Accent.svg` asset. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 095033d081b418972c7d4fe85f688841dac91a67. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") [#160](https://github.com/kernel/kernel-images/pull/160) [)](https://github.com/kernel/kernel-images/commit/089acbfef6fef8febea186ecaf34f117edd3c79e "update new brand (#160)  <!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Documentation-only updates (email/domain/link changes and a logo asset swap) with no runtime code or security-sensitive logic changes. >  > **Overview** > Updates public-facing project docs to reflect new branding: replaces `oss@onkernel.com` with `oss@kernel.sh` in `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md`, and migrates README links from `onkernel.com` to `kernel.sh`. >  > Swaps the README header logo to `static/images/logo-kernel-light.svg`, removing the old `Kernel-Wordmark_Accent.svg` asset. >  > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 095033d081b418972c7d4fe85f688841dac91a67. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->") | last monthFeb 24, 2026 |
| [bun.lock](https://github.com/kernel/kernel-images/blob/main/bun.lock "bun.lock") | [bun.lock](https://github.com/kernel/kernel-images/blob/main/bun.lock "bun.lock") | [Update README to include unikernels (](https://github.com/kernel/kernel-images/commit/e619d294f2c25a8fe627a460e0cd719012f1616a "Update README to include unikernels (#5)") [#5](https://github.com/kernel/kernel-images/pull/5) [)](https://github.com/kernel/kernel-images/commit/e619d294f2c25a8fe627a460e0cd719012f1616a "Update README to include unikernels (#5)") | 11 months agoApr 14, 2025 |
| [package.json](https://github.com/kernel/kernel-images/blob/main/package.json "package.json") | [package.json](https://github.com/kernel/kernel-images/blob/main/package.json "package.json") | [Update README to include unikernels (](https://github.com/kernel/kernel-images/commit/e619d294f2c25a8fe627a460e0cd719012f1616a "Update README to include unikernels (#5)") [#5](https://github.com/kernel/kernel-images/pull/5) [)](https://github.com/kernel/kernel-images/commit/e619d294f2c25a8fe627a460e0cd719012f1616a "Update README to include unikernels (#5)") | 11 months agoApr 14, 2025 |
| View all files |

## Repository files navigation

[![Kernel Logo](https://github.com/kernel/kernel-images/raw/main/static/images/logo-kernel-light.svg)](https://github.com/kernel/kernel-images/blob/main/static/images/logo-kernel-light.svg)

![GitHub License](https://camo.githubusercontent.com/9046277968e60431ca29ea7ac6f005bbd060d2ed375446f51acfdab3d7569707/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6f6e6b65726e656c2f6b65726e656c2d696d61676573)[![Discord](https://camo.githubusercontent.com/40b36f8b2763bcf69abac6938faece4a2131b417765dafb8ad7be03495c975ac/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f313334323234333233383734383232353535363f6c6f676f3d646973636f7264266c6f676f436f6c6f723d776869746526636f6c6f723d373238394441)](https://discord.gg/FBrveQRcud)[![Follow @juecd__](https://camo.githubusercontent.com/e79d3a8024b284d586a3b7d8fbe8cc839ef75184835317bbe6349d696d1a2e3a/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f6a756563645f5f)](https://x.com/juecd__)[![Follow @rfgarcia](https://camo.githubusercontent.com/1d60bf7a4dce5d037b5cdcace08cd46f23ca824bcdd3fd22ff02def90e74003f/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f7266676172636961)](https://x.com/rfgarcia)

## What's Kernel?

[Permalink: What's Kernel?](https://github.com/kernel/kernel-images#whats-kernel)

Kernel provides sandboxed, ready-to-use Chrome browsers for browser automations and web agents. This repo powers our [hosted services](https://kernel.sh/docs/introduction).

Sign up [here](https://www.kernel.sh/)!

## Key Features

[Permalink: Key Features](https://github.com/kernel/kernel-images#key-features)

- Sandboxed Chrome browser that Chrome DevTools-based browser frameworks (Playwright, Puppeteer) can connect to
- Remote GUI access (live view streaming) for visual monitoring and remote control
- Configurable live view settings (read-only view, browser window dimensions)
- Controllable video replays of the browser's session

## What You Can Do With It

[Permalink: What You Can Do With It](https://github.com/kernel/kernel-images#what-you-can-do-with-it)

- Run automated browser-based workflows
- Develop and test AI agents that use browsers
- Build custom tools that require controlled browser environments

## Implementation

[Permalink: Implementation](https://github.com/kernel/kernel-images#implementation)

This image can be used to run headful Chromium in a Docker container or with Unikraft unikernels. The unikernel implementation builds on top of the base Docker image and has the additional benefits of running on a unikernel:

- Automated standby / "sleep mode" when there is no network activity (consuming negligible resources when it does)
- When it goes into standby mode, the unikernel’s state gets snapshotted and can be restored exactly as it was when it went to sleep. This could be useful if you want to reuse a session’s state (browser auth cookies, interact with local files, browser settings, even the exact page and window zoom you were on).
- Extremely fast cold restarts (<20ms), which could be useful for any application that requires super low latency event handlers.

## Demo

[Permalink: Demo](https://github.com/kernel/kernel-images#demo)

kernel-images-webrtc.mp4

## Running in Docker

[Permalink: Running in Docker](https://github.com/kernel/kernel-images#running-in-docker)

You can build and run the Dockerfile directly as a Docker container.

```
cd images/chromium-headful
IMAGE=kernel-docker ./build-docker.sh
IMAGE=kernel-docker ENABLE_WEBRTC=true ./run-docker.sh
```

## Running on a Unikernel

[Permalink: Running on a Unikernel](https://github.com/kernel/kernel-images#running-on-a-unikernel)

Alternatively, you can run the browser on a Unikraft unikernel.

### 1\. Install the Kraft CLI

[Permalink: 1. Install the Kraft CLI](https://github.com/kernel/kernel-images#1-install-the-kraft-cli)

`curl -sSfL https://get.kraftkit.sh | sh`

### 2\. Add Unikraft Secret to Your CLI

[Permalink: 2. Add Unikraft Secret to Your CLI](https://github.com/kernel/kernel-images#2-add-unikraft-secret-to-your-cli)

`export UKC_METRO=<region>``export UKC_TOKEN=<secret>`

### 3\. Build the image

[Permalink: 3. Build the image](https://github.com/kernel/kernel-images#3-build-the-image)

`IMAGE=YOUR_UKC_USERNAME/chromium-headless-test:latest images/chromium-headless/build-unikernel.sh`

### 4\. Run it

[Permalink: 4. Run it](https://github.com/kernel/kernel-images#4-run-it)

`IMAGE=YOUR_UKC_USERNAME/chromium-headless-test:latest images/chromium-headless/run-unikernel.sh`
or
`IMAGE=YOUR_UKC_USERNAME/chromium-headful-test:latest VOLIMPORT_PREFIX=official images/chromium-headful/run-unikernel.sh`

When the deployment finishes successfully, the Kraft CLI will print out something like this:

```
Deployed successfully!
 │
 ├───────── name: kernel-cu
 ├───────── uuid: 0cddb958...
 ├──────── metro: <region>
 ├──────── state: starting
 ├─────── domain: https://<service_name>.kraft.host
 ├──────── image: onkernel/kernel-cu@sha256:8265f3f188...
 ├─────── memory: 8192 MiB
 ├────── service: <service_name>
 ├─ private fqdn: <id>
 ├─── private ip: <ip>
 └───────── args: /wrapper.sh
```

### Unikernel Notes

[Permalink: Unikernel Notes](https://github.com/kernel/kernel-images#unikernel-notes)

- The image requires at least 8gb of memory.
- To deploy the implementation with WebRTC desktop streaming enabled instead of noVNC: `ENABLE_WEBRTC=true NEKO_ICESERVERS=xxx ./run-unikernel.sh`
- Deploying to Unikraft Cloud requires the usage of a [TURN server](https://webrtc.org/getting-started/turn-server) when `ENABLE_WEBRTC=true`, as direct exposure of UDP ports is not currently supported. `NEKO_ICESERVERS`: Describes multiple STUN and TURN server that can be used by the ICEAgent to establish a connection with a peer. e.g. `[{"urls": ["turn:turn.example.com:19302", "stun:stun.example.com:19302"], "username": "name", "credential": "password"}, {"urls": ["stun:stun.example2.com:19302"]}]`.
- Various services (mutter, tint) take a few seconds to start-up. Once they do, the standby and restart time is extremely fast.
- The Unikraft deployment generates a url. This url is public, meaning _anyone_ can access the remote GUI if they have the url. Only use this for non-sensitive browser interactions, and delete the unikernel instance when you're done.
- You can call `browser.close()` to disconnect to the browser, and the unikernel will go into standby after network activity ends. You can then reconnect to the instance using CDP. `browser.close()` ends the websocket connection but doesn't actually close the browser.
- VCPUS value can be adjusted using the variable: `VCPUS=8`

## Connect to the browser via Chrome DevTools Protocol

[Permalink: Connect to the browser via Chrome DevTools Protocol](https://github.com/kernel/kernel-images#connect-to-the-browser-via-chrome-devtools-protocol)

Port `9222` is exposed via `ncat`, allowing you to connect Chrome DevTools Protocol-based browser frameworks like Playwright and Puppeteer (and CDP-based SDKs like Browser Use). You can use these frameworks to drive the browser in the cloud. You can also disconnect from the browser and reconnect to it.

First, fetch the browser's CDP websocket endpoint:

```
const url = new URL("http://localhost:9222/json/version");
const response = await fetch(url, {
  headers: {
    "Host": "<this can be anything>" // Required if using a unikernel
  }
});
if (response.status !== 200) {
  throw new Error(
    `Failed to retrieve browser instance: ${
      response.statusText
    } ${await response.text()}`
  );
}
// webSocketDebuggerUrl should look like:
// ws:///devtools/browser/06acd5ef-9961-431d-b6a0-86b99734f816
const { webSocketDebuggerUrl } = await response.json();
```

Then, connect a remote Playwright or Puppeteer client to it:

```
// Puppeteer
const browser = await puppeteer.connect({
  browserWSEndpoint: webSocketDebuggerUrl,
});
// Playwright
const browser = await chromium.connectOverCDP(webSocketDebuggerUrl);
```

## Browser Remote GUI / Live View

[Permalink: Browser Remote GUI / Live View](https://github.com/kernel/kernel-images#browser-remote-gui--live-view)

You can use the embedded live view to monitor and control the browser. The live view supports both read and write access to the browser. Both map to port `443`.

- NoVNC: A VNC client. Read/write is supported. Set `ENABLE_WEBRTC=false` in `./run-docker.sh`.
- WebRTC: A WebRTC-based client. Read/write, window resizing, and copy/paste is supported. It's much faster than VNC. Available when `ENABLE_WEBRTC=true` is set.

### Notes

[Permalink: Notes](https://github.com/kernel/kernel-images#notes)

- Audio streaming in the WebRTC implementation is currently non-functional and needs to be fixed.
- The live view is read/write by default. You can set it to read-only by adding `-e ENABLE_READONLY_VIEW=true \` in `docker run`.

## Replay Capture

[Permalink: Replay Capture](https://github.com/kernel/kernel-images#replay-capture)

You can use the embedded recording server to capture recordings of the entire screen in our headful images. It allows for one recording at a time and can be enabled with `WITH_KERNEL_IMAGES_API=true`

For example:

```
cd images/chromium-headful
export IMAGE=kernel-docker
./build-docker.sh
WITH_KERNEL_IMAGES_API=true ENABLE_WEBRTC=true ./run-docker.sh

# 1. Start a new recording
curl http://localhost:10001/recording/start -d {}

# recording in progress - run your agent

# 2. Stop recording
curl http://localhost:10001/recording/stop -d {}

# 3. Download the recorded file
curl http://localhost:10001/recording/download --output recording.mp4
```

Note: the recording file is encoded into a H.264/MPEG-4 AVC video file. [QuickTime has known issues with playback](https://discussions.apple.com/thread/254851789?sortBy=rank) so please make sure to use a compatible media player!

## Documentation

[Permalink: Documentation](https://github.com/kernel/kernel-images#documentation)

This repo powers our managed [browser infrastructure](https://kernel.sh/docs).

## Contributing

[Permalink: Contributing](https://github.com/kernel/kernel-images#contributing)

Please read our [contribution guidelines](https://github.com/kernel/kernel-images/blob/main/CONTRIBUTING.md) before submitting pull requests or issues.

## License

[Permalink: License](https://github.com/kernel/kernel-images#license)

See the [LICENSE](https://github.com/kernel/kernel-images/blob/main/LICENSE) file for details.

## Support

[Permalink: Support](https://github.com/kernel/kernel-images#support)

For issues, questions, or feedback, please [open an issue](https://github.com/onkernel/kernel-images/issues) on this repository. You can also join our [Discord](https://discord.gg/FBrveQRcud).

## Colophon

[Permalink: Colophon](https://github.com/kernel/kernel-images#colophon)

- Our WebRTC implementation is adapted from [Neko](https://github.com/m1k1o/neko).
- Thank you to [xonkernel](https://github.com/xonkernel) for leading the development of our WebRTC live view.
- Thank you to the [Unikraft Cloud](https://unikraft.cloud/) team for your help with unikernels.

Made with ❤️ by the [Kernel team](https://www.kernel.sh/).

## About

Browsers-as-a-service for automations and web agents


[www.kernel.sh](https://www.kernel.sh/ "https://www.kernel.sh")

### Topics

[docker](https://github.com/topics/docker "Topic: docker") [infrastructure](https://github.com/topics/infrastructure "Topic: infrastructure") [vm](https://github.com/topics/vm "Topic: vm") [browser](https://github.com/topics/browser "Topic: browser") [ai](https://github.com/topics/ai "Topic: ai") [container](https://github.com/topics/container "Topic: container") [unikernel](https://github.com/topics/unikernel "Topic: unikernel")

### Resources

[Readme](https://github.com/kernel/kernel-images#readme-ov-file)

### License

[Apache-2.0 license](https://github.com/kernel/kernel-images#Apache-2.0-1-ov-file)

### Code of conduct

[Code of conduct](https://github.com/kernel/kernel-images#coc-ov-file)

### Contributing

[Contributing](https://github.com/kernel/kernel-images#contributing-ov-file)

### Uh oh!

There was an error while loading. [Please reload this page](https://github.com/kernel/kernel-images).

[Activity](https://github.com/kernel/kernel-images/activity)

[Custom properties](https://github.com/kernel/kernel-images/custom-properties)

### Stars

[**728**\\
stars](https://github.com/kernel/kernel-images/stargazers)

### Watchers

[**3**\\
watching](https://github.com/kernel/kernel-images/watchers)

### Forks

[**45**\\
forks](https://github.com/kernel/kernel-images/forks)

[Report repository](https://github.com/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fkernel%2Fkernel-images&report=kernel+%28user%29)

## [Releases](https://github.com/kernel/kernel-images/releases)

No releases published

## [Packages\  0](https://github.com/orgs/kernel/packages?repo_name=kernel-images)

No packages published

### Uh oh!

There was an error while loading. [Please reload this page](https://github.com/kernel/kernel-images).

## [Contributors\  23](https://github.com/kernel/kernel-images/graphs/contributors)

- [![@rgarcia](https://avatars.githubusercontent.com/u/72655?s=64&v=4)](https://github.com/rgarcia)
- [![@juecd](https://avatars.githubusercontent.com/u/2819278?s=64&v=4)](https://github.com/juecd)
- [![@Sayan-](https://avatars.githubusercontent.com/u/1415138?s=64&v=4)](https://github.com/Sayan-)
- [![@cursoragent](https://avatars.githubusercontent.com/u/199161495?s=64&v=4)](https://github.com/cursoragent)
- [![@archandatta](https://avatars.githubusercontent.com/u/35818003?s=64&v=4)](https://github.com/archandatta)
- [![@hiroTamada](https://avatars.githubusercontent.com/u/88675973?s=64&v=4)](https://github.com/hiroTamada)
- [![@matthewjmarangoni](https://avatars.githubusercontent.com/u/211543057?s=64&v=4)](https://github.com/matthewjmarangoni)
- [![@ulziibay-kernel](https://avatars.githubusercontent.com/u/253135130?s=64&v=4)](https://github.com/ulziibay-kernel)
- [![@claude](https://avatars.githubusercontent.com/u/81847?s=64&v=4)](https://github.com/claude)
- [![@sjmiller609](https://avatars.githubusercontent.com/u/7516283?s=64&v=4)](https://github.com/sjmiller609)
- [![@tnsardesai](https://avatars.githubusercontent.com/u/18272584?s=64&v=4)](https://github.com/tnsardesai)
- [![@masnwilliams](https://avatars.githubusercontent.com/u/43387599?s=64&v=4)](https://github.com/masnwilliams)
- [![@raiden-staging](https://avatars.githubusercontent.com/u/216940557?s=64&v=4)](https://github.com/raiden-staging)
- [![@mertcelebi](https://avatars.githubusercontent.com/u/2692053?s=64&v=4)](https://github.com/mertcelebi)

[\+ 9 contributors](https://github.com/kernel/kernel-images/graphs/contributors)

## Languages

- [Go37.7%](https://github.com/kernel/kernel-images/search?l=go)
- [Shell27.6%](https://github.com/kernel/kernel-images/search?l=shell)
- [TypeScript11.0%](https://github.com/kernel/kernel-images/search?l=typescript)
- [Vue8.3%](https://github.com/kernel/kernel-images/search?l=vue)
- [Makefile3.7%](https://github.com/kernel/kernel-images/search?l=makefile)
- [JavaScript3.5%](https://github.com/kernel/kernel-images/search?l=javascript)
- Other8.2%

You can’t perform that action at this time.

----
url: https://www.kernel.sh/docs/api-reference/browsers/execute-a-batch-of-computer-actions-sequentially
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.batch('id', { actions: [{ type: 'click_mouse' }] });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

batch

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.computer.batch('id', { actions: [{ type: 'click_mouse' }] });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

A batch of computer actions to execute sequentially.

[​](#body-actions)

actions

object\[]

required

Ordered list of actions to execute. Execution stops on the first error.

Required array length: `1 - 100` element

s

Show child attributes

#### Response

All actions executed successfully

[Ad-hoc upload one or more unpacked extensions to a running browser instance.](https://www.kernel.sh/docs/api-reference/browsers/ad-hoc-upload-one-or-more-unpacked-extensions-to-a-running-browser-instance)

[Previous](https://www.kernel.sh/docs/api-reference/browsers/ad-hoc-upload-one-or-more-unpacked-extensions-to-a-running-browser-instance)

[Get the current mouse cursor position on the browser instance](https://www.kernel.sh/docs/api-reference/browsers/get-the-current-mouse-cursor-position-on-the-browser-instance)

[Next](https://www.kernel.sh/docs/api-reference/browsers/get-the-current-mouse-cursor-position-on-the-browser-instance)

⌘I

----
url: https://www.kernel.sh/docs/api-reference/invocations/list-browsers-for-an-invocation
----

```
{
  "browsers": [
    {
      "created_at": "2023-11-07T05:31:56Z",
      "cdp_ws_url": "wss://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/cdp?jwt=eyJ0eXAi...",
      "webdriver_ws_url": "wss://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/webdriver/session?jwt=eyJ0eXAi...",
      "headless": false,
      "stealth": false,
      "session_id": "htzv5orfit78e1m2biiifpbv",
      "timeout_seconds": 123,
      "browser_live_view_url": "https://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/live?jwt=eyJ0eXAi...",
      "gpu": false,
      "persistence": {
        "id": "my-awesome-browser-for-user-1234"
      },
      "profile": {
        "id": "<string>",
        "created_at": "2023-11-07T05:31:56Z",
        "name": "<string>",
        "updated_at": "2023-11-07T05:31:56Z",
        "last_used_at": "2023-11-07T05:31:56Z"
      },
      "proxy_id": "<string>",
      "pool": {
        "id": "<string>",
        "name": "<string>"
      },
      "viewport": {
        "width": 1280,
        "height": 800,
        "refresh_rate": 60
      },
      "kiosk_mode": false,
      "deleted_at": "2023-11-07T05:31:56Z",
      "usage": {
        "uptime_ms": 123
      }
    }
  ]
}
```

----
url: https://www.kernel.sh/docs/integrations/stagehand
----

[Stagehand](https://github.com/browserbase/stagehand) is an open source AI browser automation framework. It lets developers choose what to write in code vs. natural language. By integrating with Kernel, you can run Stagehand automations with cloud-hosted browsers.

This guide is compatible with Stagehand SDK v3. If you’re using an earlier version, please refer to the [Stagehand migration guide](https://docs.stagehand.dev/v3/migrations/v2) or upgrade to v3.

## [​](#adding-kernel-to-existing-stagehand-implementations)Adding Kernel to existing Stagehand implementations

If you already have a Stagehand (v3) implementation, you can easily switch to using Kernel’s cloud browsers by updating your browser configuration.

### [​](#1-install-the-kernel-sdk)1. Install the Kernel SDK

```
npm install @onkernel/sdk
```

### [​](#2-initialize-kernel-and-create-a-browser)2. Initialize Kernel and create a browser

Import the libraries and create a cloud browser session:

```
import { Stagehand } from "@browserbasehq/stagehand";
import Kernel from '@onkernel/sdk';
import { z } from "zod";

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create({ stealth: true });

console.log("Live view url: ", kernelBrowser.browser_live_view_url);
```

### [​](#3-update-your-browser-configuration)3. Update your browser configuration

Replace your existing browser setup to use Kernel’s CDP URL:

```
const stagehand = new Stagehand({
  env: "LOCAL",
  localBrowserLaunchOptions: {
    cdpUrl: kernelBrowser.cdp_ws_url,
  },
  model: "openai/gpt-4.1",
  apiKey: process.env.OPENAI_API_KEY,
  verbose: 1,
  domSettleTimeout: 30_000
});

await stagehand.init();
```

### [​](#4-use-your-stagehand-automation)4. Use your Stagehand automation

Use Stagehand’s page methods with the Kernel-powered browser:

```
const page = stagehand.context.pages()[0];
await page.goto("https://onkernel.com");
await stagehand.act("Click on Blog in the navbar");
await stagehand.act("Click on the newest blog post");
const output = await stagehand.extract(
  "Extract a summary of the blog post",
  z.object({ summary: z.string() })
);

console.log("Newest blog post summary: ", output.summary);

// Clean up
await stagehand.close();
await kernel.browsers.deleteByID(kernelBrowser.session_id);
```

## [​](#quick-setup-with-our-stagehand-example-app)Quick setup with our Stagehand example app

Alternatively, you can use our Kernel app template that includes a pre-configured Stagehand integration:

```
kernel create --name my-stagehand-app --language typescript --template stagehand
```

Then follow the [Quickstart guide](https://www.kernel.sh/docs/quickstart) to deploy and run your Stagehand automation on Kernel’s infrastructure.

## [​](#benefits-of-using-kernel-with-stagehand)Benefits of using Kernel with Stagehand

* **No local browser management**: Run automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel
* **Stealth mode**: Built-in anti-detection features for web scraping
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your automations with real-time browser viewing

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Stagehand app to Kernel

----
url: https://www.kernel.sh/docs/auth/programmatic
----

Build your own credential collection UI instead of using the hosted page. Poll for login fields, then submit credentials via the API. Use the Programmatic flow when:

## How It Works

## Getting started

### 1. Create a Connection

A **Managed Auth Connection** associates a [profile](https://www.kernel.sh/docs/auth/profiles) to a domain you want to keep authenticated so you can use the auth connection future browsers. Create one for each domain + profile combination you want to keep authenticated.

### 2. Start a Login Session

Credentials are saved automatically on successful login, enabling automatic re-authentication when the session expires.

### 3. Poll and Submit Credentials

A single loop handles everything—initial login, 2FA, and completion:

The `discovered_fields` array tells you what the login form needs:

## Complete Example

## Handling Different Input Types

The basic polling loop handles `discovered_fields`, but login pages can require other input types too.

### SSO Buttons

When the login page has “Sign in with Google/GitHub/Microsoft” buttons, they appear in `pending_sso_buttons`:

### MFA Selection

When the site offers multiple MFA methods, they appear in `mfa_options`:

After selecting an MFA method, the flow continues. Poll for `discovered_fields` to submit the code, or handle external actions for push/security key.

### External Actions (Push, Security Key)

When the site requires an action outside the browser (push notification, security key tap), the step becomes `AWAITING_EXTERNAL_ACTION`:

## Step Reference

The `flow_step` field indicates what the flow is waiting for:

| Step                       | Description                                                  |
| -------------------------- | ------------------------------------------------------------ |
| `DISCOVERING`              | Finding the login page and analyzing it                      |
| `AWAITING_INPUT`           | Waiting for field values, SSO button click, or MFA selection |
| `SUBMITTING`               | Processing submitted values                                  |
| `AWAITING_EXTERNAL_ACTION` | Waiting for push approval, security key, etc.                |
| `COMPLETED`                | Flow has finished                                            |

## Status Reference

The `flow_status` field indicates the current flow state:

| Status        | Description                                                    |
| ------------- | -------------------------------------------------------------- |
| `IN_PROGRESS` | Authentication is ongoing—keep polling                         |
| `SUCCESS`     | Login completed, profile saved                                 |
| `FAILED`      | Login failed (check `error_message`)                           |
| `EXPIRED`     | Flow timed out (10 minutes for user input, 20 minutes overall) |
| `CANCELED`    | Flow was canceled                                              |

The `status` field indicates the overall connection state:

| Status          | Description                           |
| --------------- | ------------------------------------- |
| `AUTHENTICATED` | Profile is logged in and ready to use |
| `NEEDS_AUTH`    | Profile needs authentication          |

## Real-Time Updates with SSE

For real-time UIs, you can stream login flow events via Server-Sent Events instead of polling:

The stream delivers `managed_auth_state` events with the same fields as polling (`flow_status`, `flow_step`, `discovered_fields`, etc.) and terminates automatically when the flow reaches a terminal state.

----
url: https://www.kernel.sh/docs/info/concepts
----

## [​](#browser)Browser

A `Browser` is a cloud-based browser managed by Kernel. They accept Chrome DevTools Protocol connections and can be used to run browser automations or web agents.

## [​](#app)App

An `App` is a codebase deployed on Kernel. You can use Kernel for a variety of use cases, including web automations, data processing, and more.

## [​](#action)Action

An `Action` is an invokable method within an app. Actions allow your to register entry points or functions that can be triggered on-demand. Actions can call non-action methods. Apps can have multiple actions.

## [​](#invocation)Invocation

An `Invocation` is a single execution of an action. Invocations can be triggered via API, scheduled as a job, or run on-demand.

----
url: https://www.kernel.sh/docs/reference/cli
----

The Kernel CLI helps you access and manage your Kernel resources.

## [​](#installation)Installation

```
# Using brew
brew install onkernel/tap/kernel

# Using pnpm
pnpm install -g @onkernel/cli

# Using npm
npm install -g @onkernel/cli
```

Verify installation:

```
which kernel
kernel --version
```

## [​](#quick-start)Quick Start

```
# 1) Create a new app
kernel create

# 2) Login
kernel login

# 3) Deploy your app
kernel deploy index.ts

# 4) Invoke your app
kernel invoke my-app action-name --payload '{"key":"value"}'
```

## [​](#global-flags)Global Flags

* `--version`, `-v` - Print the CLI version
* `--no-color` - Disable color output
* `--log-level <level>` - Set the log level (trace, debug, info, warn, error, fatal, print)

## [​](#json-output)JSON Output

Many commands support `--output json` (or `-o json`) for machine-readable output, useful for scripting and automation:

```
# Get browser session as JSON
kernel browsers create -o json

# List apps as JSON array
kernel app list -o json

# Deploy with JSONL streaming (one JSON object per line)
kernel deploy index.ts -o json
```

See individual command documentation for JSON output availability.

Looking for the API? See the [API Reference](https://www.kernel.sh/docs/api-reference/invocations/invoke-an-action).

----
url: https://www.kernel.sh/docs/reference/cli/browsers
----

## Browser sessions

### `kernel browsers list`

List all browser sessions.

| Flag                       | Description            |
| -------------------------- | ---------------------- |
| `--output json`, `-o json` | Output raw JSON array. |

### `kernel browsers create`

Create a new browser session.

| Flag                       | Description                                            |
| -------------------------- | ------------------------------------------------------ |
| `--stealth`                | Enable stealth mode to reduce automation fingerprints. |
| `--headless`               | Launch without GUI/VNC access.                         |
| `--kiosk`                  | Launch in Chrome kiosk mode.                           |
| `--output json`, `-o json` | Output raw JSON object.                                |

### `kernel browsers delete <session-id>`

Delete a browser session. Use `-y` to skip confirmation.

| Flag          | Description                     |
| ------------- | ------------------------------- |
| `--yes`, `-y` | Bypass the confirmation prompt. |

### `kernel browsers view <session-id>`

Return a live view URL for remote monitoring and control.

| Flag                       | Description                           |
| -------------------------- | ------------------------------------- |
| `--output json`, `-o json` | Output JSON with `liveViewUrl` field. |

### `kernel browsers get <session-id>`

Get detailed information about a browser session.

| Flag                       | Description             |
| -------------------------- | ----------------------- |
| `--output json`, `-o json` | Output raw JSON object. |

### `kernel browsers ssh <session-id>`

Open an interactive SSH session to a browser VM. Requires [websocat](https://github.com/vi/websocat) to be installed locally.

| Flag                          | Description                                                    |
| ----------------------------- | -------------------------------------------------------------- |
| `-i, --identity <path>`       | Path to SSH private key (generates ephemeral if not provided). |
| `-L, --local-forward <spec>`  | Local port forwarding (`localport:host:remoteport`).           |
| `-R, --remote-forward <spec>` | Remote port forwarding (`remoteport:host:localport`).          |
| `--setup-only`                | Setup SSH on VM without connecting.                            |

## Browser logs

### `kernel browsers logs stream <session-id>`

Stream browser logs from the supervisor or a file path.

| Flag                          | Description                                                      |
| ----------------------------- | ---------------------------------------------------------------- |
| `--source <source>`           | `path` or `supervisor` (required).                               |
| `--follow`                    | Continue streaming (default: true).                              |
| `--path <path>`               | File path when `--source=path`.                                  |
| `--supervisor-process <name>` | Supervisor process when `--source=supervisor` (e.g. `chromium`). |

## Replays

### `kernel browsers replays list <session-id>`

List replay recordings for a browser session.

| Flag                       | Description            |
| -------------------------- | ---------------------- |
| `--output json`, `-o json` | Output raw JSON array. |

### `kernel browsers replays start <session-id>`

Start recording a replay.

| Flag                       | Description                               |
| -------------------------- | ----------------------------------------- |
| `--framerate <fps>`        | Recording framerate in frames per second. |
| `--max-duration <seconds>` | Maximum recording duration.               |
| `--output json`, `-o json` | Output raw JSON object.                   |

### `kernel browsers replays stop <session-id> <replay-id>`

Stop an active replay recording.

### `kernel browsers replays download <session-id> <replay-id>`

Download a replay video.

| Flag                  | Description                            |
| --------------------- | -------------------------------------- |
| `-o, --output <path>` | Output path for the downloaded replay. |

## Process control

### `kernel browsers process exec <session-id> [--] [command...]`

Execute a command synchronously inside the browser VM.

| Flag                       | Description                                |
| -------------------------- | ------------------------------------------ |
| `--command <cmd>`          | Command to run; defaults to trailing args. |
| `--args <args>`            | Arguments for the command.                 |
| `--cwd <path>`             | Working directory.                         |
| `--timeout <seconds>`      | Execution timeout.                         |
| `--as-user <user>`         | Run as a specific user.                    |
| `--as-root`                | Run as root.                               |
| `--output json`, `-o json` | Output raw JSON object.                    |

### `kernel browsers process spawn <session-id> [--] [command...]`

Execute a command asynchronously in the browser VM.

| Flag                       | Description                                |
| -------------------------- | ------------------------------------------ |
| `--command <cmd>`          | Command to run; defaults to trailing args. |
| `--args <args>`            | Arguments for the command.                 |
| `--cwd <path>`             | Working directory.                         |
| `--timeout <seconds>`      | Execution timeout.                         |
| `--as-user <user>`         | Run as a specific user.                    |
| `--as-root`                | Run as root.                               |
| `--output json`, `-o json` | Output raw JSON object.                    |

### `kernel browsers process kill <session-id> <process-id>`

Send a signal to a process running in the browser VM.

| Flag                | Description                                                     |
| ------------------- | --------------------------------------------------------------- |
| `--signal <signal>` | Signal to send (`TERM`, `KILL`, `INT`, `HUP`; default: `TERM`). |

### `kernel browsers process status <session-id> <process-id>`

Check process status information.

### `kernel browsers process stdin <session-id> <process-id>`

Write base64-encoded data to a process stdin.

| Flag                | Description                         |
| ------------------- | ----------------------------------- |
| `--data-b64 <data>` | Base64 payload to write (required). |

### `kernel browsers process stdout-stream <session-id> <process-id>`

Stream stdout and stderr from a process.

## Filesystem

### `kernel browsers fs new-directory <session-id>`

Create a directory in the browser VM.

| Flag            | Description                                   |
| --------------- | --------------------------------------------- |
| `--path <path>` | Absolute directory path to create (required). |
| `--mode <mode>` | Directory mode in octal.                      |

### `kernel browsers fs delete-directory <session-id>`

Delete a directory.

| Flag            | Description                                   |
| --------------- | --------------------------------------------- |
| `--path <path>` | Absolute directory path to delete (required). |

### `kernel browsers fs delete-file <session-id>`

Delete a file.

| Flag            | Description                              |
| --------------- | ---------------------------------------- |
| `--path <path>` | Absolute file path to delete (required). |

### `kernel browsers fs download-dir-zip <session-id>`

Download a directory as a zip archive.

| Flag                  | Description                                     |
| --------------------- | ----------------------------------------------- |
| `--path <path>`       | Absolute directory path to download (required). |
| `-o, --output <path>` | Output zip file path.                           |

### `kernel browsers fs file-info <session-id>`

Retrieve metadata for a file or directory.

| Flag                       | Description                                 |
| -------------------------- | ------------------------------------------- |
| `--path <path>`            | Absolute file or directory path (required). |
| `--output json`, `-o json` | Output raw JSON object.                     |

### `kernel browsers fs list-files <session-id>`

List directory contents.

| Flag                       | Description                         |
| -------------------------- | ----------------------------------- |
| `--path <path>`            | Absolute directory path (required). |
| `--output json`, `-o json` | Output raw JSON array.              |

### `kernel browsers fs move <session-id>`

Move or rename a file or directory.

| Flag            | Description                           |
| --------------- | ------------------------------------- |
| `--src <path>`  | Absolute source path (required).      |
| `--dest <path>` | Absolute destination path (required). |

### `kernel browsers fs read-file <session-id>`

Read a file from the browser VM.

| Flag                  | Description                          |
| --------------------- | ------------------------------------ |
| `--path <path>`       | Absolute file path (required).       |
| `-o, --output <path>` | Output path for the downloaded file. |

### `kernel browsers fs set-permissions <session-id>`

Update file permissions or ownership.

| Flag              | Description                    |
| ----------------- | ------------------------------ |
| `--path <path>`   | Absolute path (required).      |
| `--mode <mode>`   | File mode bits (octal string). |
| `--owner <user>`  | New owner username or UID.     |
| `--group <group>` | New group name or GID.         |

### `kernel browsers fs upload <session-id>`

Upload one or more files.

| Flag                    | Description                                |
| ----------------------- | ------------------------------------------ |
| `--file <local:remote>` | Local-to-remote file mapping (repeatable). |
| `--dest-dir <path>`     | Destination directory for uploads.         |
| `--paths <paths>`       | Local file paths to upload.                |

### `kernel browsers fs upload-zip <session-id>`

Upload a zip file and extract it.

| Flag                | Description                           |
| ------------------- | ------------------------------------- |
| `--zip <path>`      | Local zip file path (required).       |
| `--dest-dir <path>` | Directory to extract into (required). |

### `kernel browsers fs write-file <session-id>`

Write a local file to the browser VM.

| Flag              | Description                                |
| ----------------- | ------------------------------------------ |
| `--path <path>`   | Destination absolute file path (required). |
| `--mode <mode>`   | File mode in octal.                        |
| `--source <path>` | Local source file path (required).         |

## Computer controls

### `kernel browsers computer click-mouse <session-id>`

Click the mouse at specific coordinates.

| Flag                  | Description                                                  |
| --------------------- | ------------------------------------------------------------ |
| `--x <coordinate>`    | X coordinate (required).                                     |
| `--y <coordinate>`    | Y coordinate (required).                                     |
| `--num-clicks <n>`    | Number of clicks (default: 1).                               |
| `--button <button>`   | Mouse button (`left`, `right`, `middle`, `back`, `forward`). |
| `--click-type <type>` | `down`, `up`, or `click` (default: `click`).                 |
| `--hold-key <key>`    | Modifier keys to hold (repeatable).                          |

### `kernel browsers computer move-mouse <session-id>`

Move the mouse pointer.

| Flag               | Description                         |
| ------------------ | ----------------------------------- |
| `--x <coordinate>` | X coordinate (required).            |
| `--y <coordinate>` | Y coordinate (required).            |
| `--hold-key <key>` | Modifier keys to hold (repeatable). |

### `kernel browsers computer screenshot <session-id>`

Capture a screenshot.

| Flag                | Description                           |
| ------------------- | ------------------------------------- |
| `--to <path>`       | Output PNG path (required).           |
| `--x <coordinate>`  | Region capture top-left X coordinate. |
| `--y <coordinate>`  | Region capture top-left Y coordinate. |
| `--width <pixels>`  | Region width.                         |
| `--height <pixels>` | Region height.                        |

### `kernel browsers computer type <session-id>`

Type text into the browser VM.

| Flag            | Description                               |
| --------------- | ----------------------------------------- |
| `--text <text>` | Text to type (required).                  |
| `--delay <ms>`  | Delay between keystrokes in milliseconds. |

### `kernel browsers computer press-key <session-id>`

Press one or more keys.

| Flag               | Description                         |
| ------------------ | ----------------------------------- |
| `--key <key>`      | Key to press (repeatable).          |
| `--duration <ms>`  | Duration to hold keys.              |
| `--hold-key <key>` | Modifier keys to hold (repeatable). |

### `kernel browsers computer scroll <session-id>`

Scroll the mouse wheel.

| Flag                 | Description                               |
| -------------------- | ----------------------------------------- |
| `--x <coordinate>`   | X coordinate (required).                  |
| `--y <coordinate>`   | Y coordinate (required).                  |
| `--delta-x <pixels>` | Horizontal scroll amount (+right, -left). |
| `--delta-y <pixels>` | Vertical scroll amount (+down, -up).      |
| `--hold-key <key>`   | Modifier keys to hold (repeatable).       |

### `kernel browsers computer drag-mouse <session-id>`

Drag the mouse along a path.

| Flag                | Description                                                |
| ------------------- | ---------------------------------------------------------- |
| `--point <x,y>`     | Points to drag through (repeatable).                       |
| `--delay <ms>`      | Delay before dragging starts.                              |
| `--button <button>` | Mouse button (`left`, `middle`, `right`; default: `left`). |
| `--hold-key <key>`  | Modifier keys to hold (repeatable).                        |

## Playwright

### `kernel browsers playwright execute <session-id> [code]`

Execute Playwright/TypeScript code against a running browser session.

| Flag                  | Description                             |
| --------------------- | --------------------------------------- |
| `--timeout <seconds>` | Maximum execution time for the snippet. |

## Extension management

### `kernel extensions list`

List all uploaded extensions.

| Flag                       | Description            |
| -------------------------- | ---------------------- |
| `--output json`, `-o json` | Output raw JSON array. |

### `kernel extensions upload <directory>`

Upload an unpacked extension directory.

| Flag                       | Description                     |
| -------------------------- | ------------------------------- |
| `--name <name>`            | Optional unique extension name. |
| `--output json`, `-o json` | Output raw JSON object.         |

### `kernel extensions download <id-or-name>`

Download an extension archive.

| Flag               | Description                  |
| ------------------ | ---------------------------- |
| `--to <directory>` | Output directory (required). |

### `kernel extensions download-web-store <url>`

Download an extension from the Chrome Web Store.

| Flag               | Description                                          |
| ------------------ | ---------------------------------------------------- |
| `--to <directory>` | Output directory (required).                         |
| `--os <os>`        | Target OS (`mac`, `win`, `linux`; default: `linux`). |

### `kernel extensions delete <id-or-name>`

Delete an uploaded extension.

| Flag          | Description        |
| ------------- | ------------------ |
| `--yes`, `-y` | Skip confirmation. |

### `kernel browsers extensions upload <session-id> <extension-path>...`

Upload one or more unpacked Chrome extensions directly into a running browser session.

## Proxy management

### `kernel proxies list`

List available proxy configurations.

| Flag                       | Description            |
| -------------------------- | ---------------------- |
| `--output json`, `-o json` | Output raw JSON array. |

### `kernel proxies get <id>`

Show details for a proxy configuration.

| Flag                       | Description             |
| -------------------------- | ----------------------- |
| `--output json`, `-o json` | Output raw JSON object. |

### `kernel proxies create`

Create a new proxy configuration.

| Flag                       | Description                                                           |
| -------------------------- | --------------------------------------------------------------------- |
| `--name <name>`            | Proxy configuration name.                                             |
| `--type <type>`            | `datacenter`, `isp`, `residential`, `mobile`, or `custom` (required). |
| `--protocol <protocol>`    | Protocol to use (`http` or `https`; default: `https`).                |
| `--country <code>`         | ISO 3166 country code or `EU`.                                        |
| `--city <name>`            | City (residential, mobile; requires `--country`).                     |
| `--state <code>`           | State/region code (residential, mobile).                              |
| `--zip <zip>`              | ZIP/postal code (residential, mobile).                                |
| `--asn <asn>`              | Autonomous system number (residential, mobile).                       |
| `--os <os>`                | Operating system (`windows`, `macos`, `android`; residential).        |
| `--carrier <carrier>`      | Mobile carrier (mobile).                                              |
| `--host <host>`            | Proxy host (custom; required).                                        |
| `--port <port>`            | Proxy port (custom; required).                                        |
| `--username <username>`    | Proxy username (custom).                                              |
| `--password <password>`    | Proxy password (custom).                                              |
| `--bypass-host <hostname>` | Hostname to bypass proxy (repeatable; max 100).                       |
| `--output json`, `-o json` | Output raw JSON object.                                               |

### `kernel proxies delete <id>`

Delete a proxy configuration.

| Flag          | Description        |
| ------------- | ------------------ |
| `--yes`, `-y` | Skip confirmation. |

## Browser pools

For more details on browser pools, see [Browser Pools](https://www.kernel.sh/docs/browsers/pools/overview).

### `kernel browser-pools list`

List all browser pools.

| Flag                       | Description            |
| -------------------------- | ---------------------- |
| `--output json`, `-o json` | Output raw JSON array. |

### `kernel browser-pools create`

Create a new browser pool.

| Flag                       | Description                                       |
| -------------------------- | ------------------------------------------------- |
| `--name <name>`            | Optional unique name for the pool.                |
| `--size <n>`               | Number of browsers in the pool (required).        |
| `--fill-rate <n>`          | Percentage of the pool to fill per minute.        |
| `--timeout <seconds>`      | Idle timeout for browsers acquired from the pool. |
| `--output json`, `-o json` | Output raw JSON object.                           |

### `kernel browser-pools get <id-or-name>`

Get pool details.

| Flag                       | Description             |
| -------------------------- | ----------------------- |
| `--output json`, `-o json` | Output raw JSON object. |

### `kernel browser-pools update <id-or-name>`

Update pool configuration.

| Flag                       | Description                           |
| -------------------------- | ------------------------------------- |
| `--size <n>`               | Updated pool size.                    |
| `--discard-all-idle`       | Discard all idle browsers and refill. |
| `--output json`, `-o json` | Output raw JSON object.               |

### `kernel browser-pools acquire <id-or-name>`

Acquire a browser from the pool.

| Flag                       | Description                           |
| -------------------------- | ------------------------------------- |
| `--timeout <seconds>`      | Acquire timeout before returning 204. |
| `--output json`, `-o json` | Output raw JSON object.               |

### `kernel browser-pools release <id-or-name>`

Release a browser back to the pool.

| Flag                | Description                                 |
| ------------------- | ------------------------------------------- |
| `--session-id <id>` | Browser session ID to release (required).   |
| `--reuse`           | Reuse the browser instance (default: true). |

### `kernel browser-pools delete <id-or-name>`

Delete a pool.

| Flag      | Description                               |
| --------- | ----------------------------------------- |
| `--force` | Force delete even if browsers are leased. |

### `kernel browser-pools flush <id-or-name>`

Destroy all idle browsers in the pool.

## Profiles

For more details on browser profiles, see [Profiles](https://www.kernel.sh/docs/auth/profiles).

### `kernel profiles list`

List all browser profiles.

| Flag                       | Description            |
| -------------------------- | ---------------------- |
| `--output json`, `-o json` | Output raw JSON array. |

### `kernel profiles get <id-or-name>`

Get profile details.

| Flag                       | Description             |
| -------------------------- | ----------------------- |
| `--output json`, `-o json` | Output raw JSON object. |

### `kernel profiles create`

Create a new browser profile.

| Flag                       | Description                           |
| -------------------------- | ------------------------------------- |
| `--name <name>`            | Optional unique name for the profile. |
| `--output json`, `-o json` | Output raw JSON object.               |

----
url: https://www.kernel.sh/docs/api-reference/browsers/create-a-browser-session
----

```
{
  "created_at": "2023-11-07T05:31:56Z",
  "cdp_ws_url": "wss://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/cdp?jwt=eyJ0eXAi...",
  "webdriver_ws_url": "wss://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/webdriver/session?jwt=eyJ0eXAi...",
  "headless": false,
  "stealth": false,
  "session_id": "htzv5orfit78e1m2biiifpbv",
  "timeout_seconds": 123,
  "browser_live_view_url": "https://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/live?jwt=eyJ0eXAi...",
  "gpu": false,
  "persistence": {
    "id": "my-awesome-browser-for-user-1234"
  },
  "profile": {
    "id": "<string>",
    "created_at": "2023-11-07T05:31:56Z",
    "name": "<string>",
    "updated_at": "2023-11-07T05:31:56Z",
    "last_used_at": "2023-11-07T05:31:56Z"
  },
  "proxy_id": "<string>",
  "pool": {
    "id": "<string>",
    "name": "<string>"
  },
  "viewport": {
    "width": 1280,
    "height": 800,
    "refresh_rate": 60
  },
  "kiosk_mode": false,
  "deleted_at": "2023-11-07T05:31:56Z",
  "usage": {
    "uptime_ms": 123
  }
}
```

```
{
  "created_at": "2023-11-07T05:31:56Z",
  "cdp_ws_url": "wss://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/cdp?jwt=eyJ0eXAi...",
  "webdriver_ws_url": "wss://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/webdriver/session?jwt=eyJ0eXAi...",
  "headless": false,
  "stealth": false,
  "session_id": "htzv5orfit78e1m2biiifpbv",
  "timeout_seconds": 123,
  "browser_live_view_url": "https://proxy.yul-upbeat-herschel.onkernel.com:8443/browser/live?jwt=eyJ0eXAi...",
  "gpu": false,
  "persistence": {
    "id": "my-awesome-browser-for-user-1234"
  },
  "profile": {
    "id": "<string>",
    "created_at": "2023-11-07T05:31:56Z",
    "name": "<string>",
    "updated_at": "2023-11-07T05:31:56Z",
    "last_used_at": "2023-11-07T05:31:56Z"
  },
  "proxy_id": "<string>",
  "pool": {
    "id": "<string>",
    "name": "<string>"
  },
  "viewport": {
    "width": 1280,
    "height": 800,
    "refresh_rate": 60
  },
  "kiosk_mode": false,
  "deleted_at": "2023-11-07T05:31:56Z",
  "usage": {
    "uptime_ms": 123
  }
}
```

Parameters for creating a browser session.

Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (1920x1080\@25). For GPU images, the default is 1920x1080\@60. Arbitrary viewport dimensions and refresh rates are accepted. Known-good presets include: 2560x1440\@10, 1920x1080\@25, 1920x1200\@25, 1440x900\@25, 1280x800\@60, 1024x768\@60, 1200x800\@60. For GPU images, recommended presets use one of these resolutions with refresh rates 60, 30, 25, or 10: 800x600, 960x720, 1024x576, 1024x768, 1152x648, 1200x800, 1280x720, 1368x768, 1440x900, 1600x900, 1920x1080, 1920x1200, 390x844, 360x250, 768x1024, 800x1600. Viewports outside this list may exhibit unstable live view or recording behavior. If refresh\_rate is not provided, it will be automatically determined based on the resolution (higher resolutions use lower refresh rates to keep bandwidth reasonable).

Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (1920x1080\@25). For GPU images, the default is 1920x1080\@60. Arbitrary viewport dimensions and refresh rates are accepted. Known-good presets include: 2560x1440\@10, 1920x1080\@25, 1920x1200\@25, 1440x900\@25, 1280x800\@60, 1024x768\@60, 1200x800\@60. For GPU images, recommended presets use one of these resolutions with refresh rates 60, 30, 25, or 10: 800x600, 960x720, 1024x576, 1024x768, 1152x648, 1200x800, 1280x720, 1368x768, 1440x900, 1600x900, 1920x1080, 1920x1200, 390x844, 360x250, 768x1024, 800x1600. Viewports outside this list may exhibit unstable live view or recording behavior. If refresh\_rate is not provided, it will be automatically determined based on the resolution (higher resolutions use lower refresh rates to keep bandwidth reasonable).

----
url: https://www.kernel.sh/docs/browsers/viewport
----

Kernel browsers allow you to configure the viewport size and refresh rate when creating a browser session. The viewport configuration determines the initial browser window dimensions and display refresh rate. The refresh rate can be explicitly specified or automatically determined based on the width and height if they match a supported configuration.

## Default viewport

If the `viewport` parameter is omitted when creating a browser, the default configuration is 1920x1080 at 25Hz.

## Setting viewport configuration

You can configure the viewport when creating a browser by specifying the `viewport` parameter with `width` and `height`. The `refresh_rate` is optional and will be automatically determined from the dimensions if they match a supported configuration:

## Supported viewport configurations

Kernel supports specific viewport configurations tuned for optimal performance and Computer Use compatibility. When you provide width and height without specifying refresh\_rate, it will be automatically determined if the dimensions match one of the supported resolutions exactly. The following resolutions are supported:

| Resolution | Width | Height | Refresh Rate |
| ---------- | ----- | ------ | ------------ |
| QHD        | 2560  | 1440   | 10 Hz        |
| Full HD    | 1920  | 1080   | 25 Hz        |
| WUXGA      | 1920  | 1200   | 25 Hz        |
| WXGA+      | 1440  | 900    | 25 Hz        |
| WXGA       | 1280  | 800    | 60 Hz        |
| WXGA       | 1200  | 800    | 60 Hz        |
| XGA        | 1024  | 768    | 60 Hz        |
| Tablet     | 768   | 1024   | 60 Hz        |
| Mobile     | 390   | 844    | 60 Hz        |

When specifying a viewport:

## Example configurations

## Dynamically changing the viewport

You can change the viewport of a browser after it has been created using the [update browser endpoint](https://www.kernel.sh/docs/api-reference/browsers/update-browser-session).

### Force resizing during recording

If you need to resize the viewport while a replay is actively recording, set `force` to `true` in the update request. This stops the current recording, resizes the viewport, and restarts the recording — resulting in multiple replay segments for the session.

## Considerations

----
url: https://www.kernel.sh/docs/introduction
----

Kernel is a developer platform that provides Crazy Fast Browsers-as-a-Service for browser automations and web agents. Our API and MCP server allow you to instantly launch browsers in the cloud without managing infrastructure.

## [​](#connect-over-cdp)Connect over CDP

If you are already familiar with browser vendors, you can immediately start using our browsers with `kernel.browsers.create()`. We return a **CDP url** that you can connect any Playwright or Puppeteer automation to.

Install the Kernel SDK with `npm install @onkernel/sdk` or `uv pip install kernel`

```
import Kernel from '@onkernel/sdk';
import { chromium } from 'playwright';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create();
const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url);
```

## [​](#kernel-app-platform)Kernel app platform

If you’re new to building web agents or browser automations, our platform provides a full-featured code execution platform for hosting and invoking your automations in production. Follow our [quickstart guide](https://www.kernel.sh/docs/quickstart#getting-started) to get started.

## [​](#why-kernel)Why Kernel?

Developers love our platform for its performance, developer experience, and all the other niceties that would otherwise be impractical to homeroll yourself:

* **Serverless browsers** - Connect your web automation to our cloud-based browsers without managing infrastructure
* **Long-lived session states** - Securely authenticate on behalf of your users with [Managed Auth](https://www.kernel.sh/docs/auth/overview). Browsers can run for up to 72 hours via [timeout configuration](https://www.kernel.sh/docs/browsers/termination)
* **Live view** - Support human-in-the-loop workflows
* **Replays** - Review past browser sessions as video replays
* **Full isolation** - Kernel browsers are sandboxed in individual, isolated virtual machines
* **Parallel scaling** - Run hundreds or thousands of concurrent browsers at scale
* **Simple, predictable pricing** - We only charge for active browser time

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/move-or-rename-a-file-or-directory
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.move('id', { dest_path: '/J!', src_path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

move

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.move('id', { dest_path: '/J!', src_path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-src-path)

src\_path

string

required

Absolute source path.

Pattern: `^/.*`

[​](#body-dest-path)

dest\_path

string

required

Absolute destination path.

Pattern: `^/.*`

#### Response

Move successful

[Get information about a file or directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/get-information-about-a-file-or-directory)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/get-information-about-a-file-or-directory)

[Watch a directory for changes](https://www.kernel.sh/docs/api-reference/browser-filesystem/watch-a-directory-for-changes)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/watch-a-directory-for-changes)

Ctrl+I

----
url: https://www.kernel.sh/docs/browsers/faq
----

## [​](#browser-spin-up-time)Browser spin-up time

Non-standard configuration can affect browser spin-up time. Settings like non-default [viewport sizing](https://www.kernel.sh/docs/browsers/viewport), [extensions](https://www.kernel.sh/docs/browsers/extensions), or [Profiles](https://www.kernel.sh/docs/auth/profiles) may increase the time it takes for a browser to become ready. **Standard configuration** includes:

* Headful and headless browsers
* Stealth mode both enabled and disabled

If you’re experiencing slower-than-expected browser creation times, review your configuration to identify any non-standard settings that may be contributing to the delay.

## [​](#connection-notes)Connection notes

* **CDP connections** are meant to be long-lived but may eventually close. Websocket connections typically can remain active for up to 1 hour, after which they may close automatically. Browser sessions themselves are unaffected—reconnect to the same `cdp_ws_url` to continue using the browser.
* Browsers persist independently of CDP. Depending on your timeout configuration, it will continue running even if the CDP connection closes. You can reconnect to the same `cdp_ws_url` if you’re unexpectedly disconnected.
* We recommend implementing reconnect logic, as network interruptions or lifecycle events can cause CDP sessions to close. Detect disconnects and automatically re-establish a CDP connection when this occurs.

## [​](#unsupported-websites)Unsupported Websites

There are some websites that are not supported by Kernel browsers due to their restrictions around automation and associated bot detection. These include:

* LinkedIn
* Facebook
* Instagram
* X (Twitter)
* Amazon
* Reddit

----
url: https://www.kernel.sh/docs/proxies/overview
----

Kernel proxies enable you to route browser traffic through different types of proxy servers, providing enhanced privacy, flexibility, and bot detection avoidance. Proxies can be created once and reused across multiple browser sessions.

## Proxy Types

Kernel supports four types of proxies:

1. [**Datacenter**](https://www.kernel.sh/docs/proxies/datacenter) - Traffic routed through commercial data centers
2. [**ISP**](https://www.kernel.sh/docs/proxies/isp) - Traffic routed through data centers, using residential IP addresses leased from from internet service providers
3. [**Residential**](https://www.kernel.sh/docs/proxies/residential) - Traffic routed through real residential IP addresses
4. [**Custom**](https://www.kernel.sh/docs/proxies/custom) - Your own proxy servers

Datacenter has the fastest speed, while residential is least detectable. ISP is a balance between the two options, with less-flexible geotargeting. Kernel recommends to use the first option in the list that works for your use case.

## 1. Create a proxy

Create a proxy configuration from the types above that can be reused across browser sessions:

## 2. List your proxies

View all proxy configurations in your organization:

## 3. Use with browsers

Once created, you can attach a proxy to any browser session using the `proxy_id` parameter:

## 4. Bypass hosts

Configure specific hostnames to bypass the proxy and connect directly. This is useful for accessing internal services, metadata endpoints, or reducing latency for trusted domains.

### Bypass host rules

## 5. Update a browser’s proxy

You can hot-swap the proxy on a running browser session without restarting it. This updates the proxy configuration immediately — all subsequent network requests from the browser will use the new proxy.

The update is synchronous — when the call returns, the proxy swap is fully applied and all new browser traffic routes through the updated proxy. The swap typically completes in 2–3 seconds.

## 6. Delete a proxy

When no longer needed, delete the proxy configuration:

----
url: https://www.kernel.sh/docs/integrations/vibium
----

[Vibium](https://github.com/VibiumDev/vibium) is a brand-new browser automation framework for AI agents that is built on WebDriver BiDi, a W3C standard. As of [v26.3.9](https://github.com/VibiumDev/vibium/releases/tag/v26.3.9), any agent can now use Vibium to connect to Kernel cloud browsers to navigate pages, fill forms, click buttons, and take screenshots. We’re really excited to keep working with Jason Huggins and to keep supporting open web standards.

## [​](#adding-kernel-to-existing-vibium-implementations)Adding Kernel to existing Vibium implementations

If you already have a Vibium implementation, you can switch to using Kernel’s cloud browsers by creating a Kernel browser session and connecting Vibium to the returned `webdriver_ws_url`.

### [​](#1-install-kernel-and-vibium)1. Install Kernel and Vibium

```
npm install -g @onkernel/cli vibium
```

### [​](#2-create-a-kernel-browser)2. Create a Kernel browser

```
browser_json="$(kernel browsers create -o json)"
session_id="$(printf '%s' "$browser_json" | jq -r '.session_id')"
webdriver_ws_url="$(printf '%s' "$browser_json" | jq -r '.webdriver_ws_url')"
```

### [​](#3-connect-vibium-to-your-kernel-browser)3. Connect Vibium to your Kernel browser

```
vibium start "$webdriver_ws_url"
```

### [​](#4-use-your-vibium-automation)4. Use your Vibium automation

Use Vibium’s page methods with the Kernel-powered browser:

```
vibium go https://example.com
vibium title        # "Example Domain"
vibium text h1      # "Example Domain"
```

### [​](#5-clean-up)5. Clean up

When you’re done, close Vibium and delete the Kernel browser session:

```
vibium stop
kernel browsers delete "$session_id"
```

## [​](#using-vibium-cli-with-kernel)Using Vibium CLI with Kernel

The CLI can connect directly to the Kernel browser’s WebDriver BiDi endpoint:

```
export KERNEL_API_KEY=<your kernel api key>

browser_json="$(kernel browsers create -o json)"
session_id="$(printf '%s' "$browser_json" | jq -r '.session_id')"
webdriver_ws_url="$(printf '%s' "$browser_json" | jq -r '.webdriver_ws_url')"

vibium start "$webdriver_ws_url"

vibium go https://example.com
vibium title        # "Example Domain"
vibium text h1      # "Example Domain"

vibium stop
kernel browsers delete "$session_id"
```

## [​](#using-vibium-mcp-server-with-kernel)Using Vibium MCP server with Kernel

The MCP server reads the same environment variable, so AI agents can use a Kernel-powered browser:

```
VIBIUM_CONNECT_URL=<your-kernel-webdriver-ws-url> vibium mcp
```

Or in your Claude Desktop / Claude Code config:

```
{
  "mcpServers": {
    "vibium": {
      "command": "vibium",
      "args": ["mcp"],
      "env": {
        "VIBIUM_CONNECT_URL": "<your-kernel-webdriver-ws-url>"
      }
    }
  }
}
```

## [​](#benefits-of-using-kernel-with-vibium)Benefits of using Kernel with Vibium

* **No local browser management**: Run automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel
* **Stealth mode**: Built-in anti-detection features for web scraping
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/profiles/overview)
* **Live view**: Debug your automations with real-time browser viewing

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Vibium app to Kernel

----
url: https://www.kernel.sh/docs/integrations/computer-use/gemini
----

[Gemini 2.5 Computer Use](https://blog.google/technology/google-deepmind/gemini-computer-use-model/) is Google’s groundbreaking capability that enables AI models to interact with computers the way humans do—by looking at screens, moving cursors, clicking buttons, and typing text. This powerful feature allows AI agents to control web browsers, navigate interfaces, and perform complex tasks across applications. By integrating Gemini 2.5 Computer Use with Kernel, you can run these AI-powered browser automations on cloud-hosted infrastructure, eliminating the need for local browser management and enabling scalable, reliable AI agents.

## [​](#quick-setup-with-computer-use)Quick setup with Computer Use

Get started with Gemini Computer Use and Kernel using our pre-configured app template:

```
kernel create --name my-computer-use-app --language typescript --template gemini-computer-use
```

Then follow the [Quickstart guide](https://www.kernel.sh/docs/quickstart) to deploy and run your Computer Use automation on Kernel’s infrastructure.

## [​](#benefits-of-using-kernel-with-computer-use)Benefits of using Kernel with Computer Use

* **No local browser management**: Run Computer Use automations without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel for concurrent AI agents
* **Stealth mode**: Built-in anti-detection features for reliable web interactions
* **Session state**: Maintain browser state across runs via [Profiles](https://www.kernel.sh/docs/auth/profiles)
* **Live view**: Debug your Computer Use agents with real-time browser viewing
* **Cloud infrastructure**: Run computationally intensive AI agents without local resource constraints

## [​](#next-steps)Next steps

* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your Computer Use automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Learn how to properly [terminate browser sessions](https://www.kernel.sh/docs/browsers/termination)
* Learn how to [deploy](https://www.kernel.sh/docs/apps/deploy) your Computer Use app to Kernel

----
url: https://www.kernel.sh/docs/api-reference/invocations/stream-invocation-events-via-sse
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.invocations.follow('id');

console.log(response);
```

```
{
  "event": "<string>",
  "timestamp": "2023-11-07T05:31:56Z",
  "message": "<string>"
}
```

GET

/

invocations

/

{id}

/

events

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.invocations.follow('id');

console.log(response);
```

```
{
  "event": "<string>",
  "timestamp": "2023-11-07T05:31:56Z",
  "message": "<string>"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

The invocation ID to follow.

#### Query Parameters

[​](#parameter-since)

since

string

Show logs since the given time (RFC timestamps or durations like 5m).

Example:

`"2025-06-20T12:00:00Z"`

#### Response

SSE stream of invocation state updates and logs.

* Option 1

* Option 2

* Option 3

* Option 4

Union type representing any invocation event.

[Delete browser sessions for an invocation](https://www.kernel.sh/docs/api-reference/invocations/delete-browser-sessions-for-an-invocation)

[Previous](https://www.kernel.sh/docs/api-reference/invocations/delete-browser-sessions-for-an-invocation)

[List proxies](https://www.kernel.sh/docs/api-reference/proxies/list-proxies)

[Next](https://www.kernel.sh/docs/api-reference/proxies/list-proxies)

Ctrl+I

----
url: https://www.kernel.sh/docs/apps/status
----

Once you’ve [deployed](https://www.kernel.sh/docs/apps/deploy) an app and invoked it, you can monitor its status using streaming for real-time updates or polling for periodic checks.

An invocation ends once its code execution finishes.

## [​](#streaming-status-updates)Streaming Status Updates

For real-time status monitoring, use `follow` to [stream invocation events](https://www.kernel.sh/docs/api-reference/invocations/stream-invocation-events-via-sse). This provides immediate updates as your invocation progresses and is more efficient than polling.

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const response = await kernel.invocations.follow('id');
console.log(response);
```

### [​](#example)Example

Here’s an example showing how to handle streaming status updates:

Typescript/Javascript

```
const result = await kernel.invocations.retrieve(invocation.id);
const follow = await kernel.invocations.follow(result.id);

for await (const evt of follow) {
  if (evt.event === 'invocation_state') {
    console.log(`Status: ${evt.invocation.status}`);

    if (evt.invocation.status === 'succeeded') {
      console.log('Invocation completed successfully');
      if (evt.invocation.output) {
        console.log('Result:', JSON.parse(evt.invocation.output));
      }
      break;
    } else if (evt.invocation.status === 'failed') {
      console.log('Invocation failed');
      if (evt.invocation.status_reason) {
        console.log('Error:', evt.invocation.status_reason);
      }
      break;
    }
  } else if (evt.event === 'error') {
    console.error('Error:', evt.error.message);
    break;
  }
}
```

## [​](#polling-status-updates)Polling Status Updates

Alternatively, you can poll the status endpoint using `retrieve` to check the invocation status periodically.

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const invocation = await kernel.invocations.retrieve('rr33xuugxj9h0bkf1rdt2bet');
console.log(invocation.status);
```

----
url: https://www.kernel.sh/docs/browsers/bot-detection/web-bot-auth
----

[Web Bot Auth](https://datatracker.ietf.org/doc/html/draft-meunier-web-bot-auth-architecture) is quickly becoming the standard way for agents to establish identity. That’s why we’ve partnered with [Vercel](https://bots.fyi/d/kernel) to support Web Bot Auth on Kernel. You can now cryptographically sign browser requests, so your agents can prove who they are to services like Vercel.

## [​](#how-it-works)How it works

Web Bot Auth works via a Chrome extension that intercepts all outgoing HTTP requests and adds cryptographic signature headers:

* **`Signature`**: The RFC 9421 signature of the request
* **`Signature-Input`**: Metadata about how the signature was created
* **`Signature-Agent`**: URL that points to your key directory

Platforms like [Vercel](https://bots.fyi/) or other hosting providers can verify these signatures against your public key, confirming that the request came from your authenticated agent.

## [​](#quick-start-with-test-key)Quick start with test key

The fastest way to get started is using a test key, which works with this [test verification site](https://http-message-signatures-example.research.cloudflare.com/).

### [​](#1-build-the-extension)1. Build the extension

Use the Kernel CLI to build the Web Bot Auth extension:

```
kernel extensions build-web-bot-auth --to ./web-bot-auth-ext --upload my-web-bot-auth
```

The build command requires Node.js and npm to be installed on your system.

### [​](#2-create-a-browser-with-the-extension)2. Create a browser with the extension

```
# Create a browser with the web-bot-auth extension
kernel browsers create --extension my-web-bot-auth

# The command outputs the browser ID and live view URL
# Open the live view URL in your browser, then navigate to:
# https://http-message-signatures-example.research.cloudflare.com/
```

### [​](#3-verify-it’s-working)3. Verify it’s working

Navigate to the [test site](https://http-message-signatures-example.research.cloudflare.com/) to verify your signatures are being accepted: This site validates requests signed with the RFC9421 test key and shows whether the signature was verified successfully.

## [​](#using-your-own-keys)Using your own keys

For production use, you’ll want to use your own signing keys instead of the test key.

### [​](#1-generate-an-ed25519-key-pair)1. Generate an Ed25519 key pair

Create a JWK file with your Ed25519 private key. The key must include both the public (`x`) and private (`d`) components:

my-key.jwk

```
{
  "kty": "OKP",
  "crv": "Ed25519",
  "x": "YOUR_PUBLIC_KEY_BASE64URL",
  "d": "YOUR_PRIVATE_KEY_BASE64URL"
}
```

See [web-bot-auth documentation](https://github.com/cloudflare/web-bot-auth) for tools to generate Ed25519 key pairs.

### [​](#2-host-your-public-key)2. Host your public key

For websites to verify your signatures, you need to host your public key at a well-known URL. Create a key directory at:

```
https://yourdomain.com/.well-known/http-message-signatures-directory
```

The directory should contain your public keys in JWKS format:

```
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "YOUR_PUBLIC_KEY_BASE64URL",
      "kid": "YOUR_KEY_ID"
    }
  ],
  "purpose": "your-bot-purpose"
}
```

### [​](#3-build-with-your-key-and-hosted-key-directory)3. Build with your key and hosted key directory

```
kernel extensions build-web-bot-auth \
  --to ./web-bot-auth-ext \
  --key ./my-key.jwk \
  --url https://yourdomain.com/.well-known/http-message-signatures-directory \
  --upload my-web-bot-auth
```

### [​](#4-register-with-vercel-and-other-web-bot-auth-aware-directories-optional)4. Register with Vercel and other Web Bot Auth-aware directories (optional)

If you want Vercel-protected sites to recognize your agent, you can register your key directory with [Vercel](https://bots.fyi/new-bot). Kernel is officially listed in the Vercel directory.

## [​](#references)References

* [Vercel’s Public Directory](https://bots.fyi/?query=kernel)
* [Web Bot Auth GitHub Repository](https://github.com/cloudflare/web-bot-auth)
* [Web Bot Auth Documentation](https://developers.cloudflare.com/bots/reference/bot-verification/web-bot-auth/)
* [RFC 9421 - HTTP Message Signatures](https://datatracker.ietf.org/doc/html/rfc9421)
* [Test Verification Site](https://http-message-signatures-example.research.cloudflare.com/)
* [Web Bot Auth Architecture Draft](https://thibmeu.github.io/http-message-signatures-directory/draft-meunier-web-bot-auth-architecture.html)

----
url: https://www.kernel.sh/docs/proxies/isp
----

ISP (Internet Service Provider) proxies combine the speed of datacenter proxies with better legitimacy, as they use IP addresses assigned by real ISPs.

## [​](#configuration)Configuration

Create an ISP proxy:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const proxy = await kernel.proxies.create({
  type: 'isp',
  name: 'my-isp-proxy',
});

const browser = await kernel.browsers.create({
  proxy_id: proxy.id,
});
```

## [​](#configuration-parameters)Configuration Parameters

* **`bypass_hosts`** (optional) - Array of hostnames that bypass the proxy and connect directly (max 100 entries)

## [​](#bypass-hosts)Bypass hosts

Configure specific hostnames to bypass the proxy:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const proxy = await kernel.proxies.create({
  type: 'isp',
  name: 'isp-with-bypass',
  bypass_hosts: [
    'localhost',
    'internal.service.local',
    '*.amazonaws.com',
  ],
});
```

See the [overview](https://www.kernel.sh/docs/proxies/overview#bypass-hosts) for full bypass host rules and examples.

----
url: https://www.kernel.sh/docs/api-reference/managed-auth/get-auth-connection
----

```
{
  "id": "ma_abc123xyz",
  "profile_name": "my-netflix-profile",
  "domain": "netflix.com",
  "status": "AUTHENTICATED",
  "save_credentials": true,
  "last_auth_at": "2025-01-15T10:30:00Z",
  "credential": {
    "name": "my-netflix-creds",
    "provider": "my-1p",
    "path": "Personal/Netflix",
    "auto": true
  },
  "can_reauth": true,
  "can_reauth_reason": "has_credential",
  "proxy_id": "<string>",
  "allowed_domains": [
    "login.netflix.com",
    "auth.netflix.com"
  ],
  "post_login_url": "https://www.netflix.com/browse",
  "flow_status": "IN_PROGRESS",
  "flow_step": "AWAITING_INPUT",
  "flow_type": "LOGIN",
  "flow_expires_at": "2025-11-05T20:00:00Z",
  "discovered_fields": [
    {
      "name": "email",
      "type": "email",
      "label": "Email address",
      "selector": "input#email",
      "placeholder": "you@example.com",
      "required": true,
      "linked_mfa_type": "sms"
    }
  ],
  "mfa_options": [
    {
      "type": "sms",
      "label": "Text me a code",
      "target": "***-***-5678",
      "description": "We'll send a 6-digit code to your phone"
    }
  ],
  "pending_sso_buttons": [
    {
      "selector": "xpath=//button[contains(text(), 'Continue with Google')]",
      "provider": "google",
      "label": "Continue with Google"
    }
  ],
  "external_action_message": "Tap 'Yes' on the Google prompt on your phone",
  "website_error": "<string>",
  "sso_provider": "google",
  "error_message": "Invalid password",
  "error_code": "<string>",
  "hosted_url": "https://auth.kernel.com/login/abc123xyz",
  "live_view_url": "https://live.kernel.com/abc123xyz",
  "health_check_interval": 3600
}
```

----
url: https://www.kernel.sh/docs/migrations/scrapybara
----

[Scrapybara](https://scrapybara.com/) has shut down their virtual desktop and browser service as of **October 15, 2025**. If you were using Scrapybara for browser automation, Kernel is here to help you migrate seamlessly.

## Key Concepts

| Feature           | Scrapybara                                                              | Kernel                                                                                                                                                            |
| ----------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Start Browser** | `client.start_browser()`                                                | `kernel.browsers.create()`                                                                                                                                        |
| **Standby Mode**  | `instance.pause()` / `instance.resume()`                                | Automatic standby mode                                                                                                                                            |
| **CDP URL**       | `instance.get_cdp_url().cdp_url`                                        | Returns `cdp_ws_url` in create response                                                                                                                           |
| **Live View**     | `instance.get_stream_url().stream_url`                                  | Returns `browser_live_view_url` in create response                                                                                                                |
| **Stealth Mode**  | ❌ Not available                                                         | Create browser with `stealth: true`                                                                                                                               |
| **Replays**       | ❌ Not available                                                         | `kernel.browsers.replays.start()` and `kernel.browsers.replays.stop()`                                                                                            |
| **Save Auth**     | `instance.browser.save_auth(name="default")`                            | Create [Profile](https://www.kernel.sh/docs/auth/profiles). Then create browser with `kernel.browsers.create(profile={"name": "profile1", "save_changes": true})` |
| **Click**         | `instance.computer(action="click_mouse", button="left")`                | `kernel.browsers.computer.click_mouse(id=session_id, x=100, y=200)`                                                                                               |
| **Drag**          | `instance.computer(action="drag_mouse", path=[[100, 200], [300, 400]])` | `kernel.browsers.computer.drag_mouse(id=session_id, path=[[100, 200], [150, 220], [200, 260]])`                                                                   |
| **Screenshot**    | `instance.computer(action="take_screenshot").base64_image`              | `kernel.browsers.computer.capture_screenshot(id=session_id)`                                                                                                      |

## How to migrate

### Basic Browser Creation

**Scrapybara**

**Kernel**

### Save & Reuse Authentication

**Scrapybara**

**Kernel**

### File Download

**Scrapybara**

**Kernel**

### Long-Running Sessions

**Scrapybara**

**Kernel**

### Computer Controls

Both Scrapybara and Kernel provide Computer Controls APIs that allow you to programmatically control the browser environment at the system level - including mouse movements, clicks, keyboard input, and screenshots. **Scrapybara**

**Kernel**

```
kernel_browser = await kernel.browsers.create()

# Click at specific coordinates
kernel.browsers.computer.click_mouse(
    id=kernel_browser.session_id,
    x=100,
    y=200
)

# Drag from one position to another
kernel.browsers.computer.drag_mouse(
    id=kernel_browser.session_id,
    path=[[100, 200], [150, 220], [200, 260]],
    button="left",
    delay=0,
    steps_per_segment=10,
    step_delay_ms=50,
    hold_keys=["Shift"]
)

# Type text with optional delay
kernel.browsers.computer.type_text(
    id=kernel_browser.session_id,
    text="Hello World",
    delay=100
)

# Take a full screenshot
with open('screenshot.png', 'wb') as f:
    image_data = kernel.browsers.computer.capture_screenshot(id=kernel_browser.session_id)
    f.write(image_data.read())
```

For a complete reference of all available Computer Controls methods in Kernel, see the [Computer Controls documentation](https://www.kernel.sh/docs/browsers/computer-controls).

## Full API Comparison

| Feature                 | Scrapybara                                                                           | Kernel                                                                                                                                                            |
| ----------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Create Browser**      | `client.start_browser()`                                                             | `kernel.browsers.create()`                                                                                                                                        |
| **Get CDP URL**         | `instance.get_cdp_url().cdp_url`                                                     | Returns `cdp_ws_url` in create response                                                                                                                           |
| **Get Live View**       | `instance.get_stream_url().stream_url`                                               | Returns `browser_live_view_url` in create response                                                                                                                |
| **Delete Browser**      | `instance.stop()`                                                                    | `kernel.browsers.delete_by_id(session_id)`                                                                                                                        |
| **List Browsers**       | `kernel.get_instances()`                                                             | `kernel.browsers.list()`                                                                                                                                          |
| **Save Auth State**     | `instance.browser.save_auth(name="default")`                                         | Create [Profile](https://www.kernel.sh/docs/auth/profiles). Then create browser with `kernel.browsers.create(profile={"name": "profile1", "save_changes": True})` |
| **Load Auth State**     | `instance.browser.authenticate(auth_state_id="xyz")`                                 | `kernel.browsers.create(profile={"name": "profile1"})`                                                                                                            |
| **Pause/Resume**        | `instance.pause()` / `instance.resume()`                                             | Automatic standby mode                                                                                                                                            |
| **Screenshot**          | `instance.screenshot()`                                                              | Use Playwright or Puppeteer                                                                                                                                       |
| **Timeout Config**      | `timeout_hours` parameter                                                            | `timeout_seconds` parameter                                                                                                                                       |
| **Stealth Mode**        | ❌ Not available                                                                      | Create browser with `stealth: true`                                                                                                                               |
| **Headless Mode**       | ❌ Not available                                                                      | Create browser with `headless: true`                                                                                                                              |
| **Session Persistence** | Auth state only                                                                      | Full browser state via creating browser with extended timeout                                                                                                     |
| **Video Replays**       | ❌ Not available                                                                      | `kernel.browsers.replays.start()` and `kernel.browsers.replays.stop()`                                                                                            |
| **File Upload**         | `instance.upload()`                                                                  | `kernel.browsers.fs.upload()` or Playwright                                                                                                                       |
| **File Download**       | Via browser, then `instance.file()`                                                  | `kernel.browsers.fs.read_file()`                                                                                                                                  |
| **Process Control**     | `instance.bash()`                                                                    | `kernel.browsers.process.*`                                                                                                                                       |
| **Proxy Support**       | ❌ Not available                                                                      | Create [Proxy](https://www.kernel.sh/docs/proxies/overview#1-create-a-proxy). Then create browser with `kernel.browsers.create(proxy_id=proxy.id)`                |
| **Click Mouse**         | `instance.computer(action="click_mouse", button="left")`                             | `kernel.browsers.computer.click_mouse(id=session_id, x=100, y=200)`                                                                                               |
| **Move Mouse**          | `instance.computer(action="move_mouse", coordinates=[100, 200])`                     | `kernel.browsers.computer.move_mouse(id=session_id, x=100, y=200)`                                                                                                |
| **Drag Mouse**          | `instance.computer(action="drag_mouse", path=[[100, 200], [300, 400]])`              | `kernel.browsers.computer.drag_mouse(id=session_id, path=[[100, 200], [150, 220], [200, 260]])`                                                                   |
| **Scroll**              | `instance.computer(action="scroll", coordinates=[100, 100], delta_x=0, delta_y=200)` | `kernel.browsers.computer.scroll(id=session_id, delta_x=0, delta_y=100)`                                                                                          |
| **Type Text**           | `instance.computer(action="type_text", text="Hello")`                                | `kernel.browsers.computer.type_text(id=session_id, text="Hello")`                                                                                                 |
| **Press Key**           | `instance.computer(action="press_key", keys=["ctrl", "c"])`                          | `kernel.browsers.computer.press_key(id=session_id, keys=["Ctrl+t"])`                                                                                              |
| **Take Screenshot**     | `instance.computer(action="take_screenshot").base64_image`                           | `kernel.browsers.computer.capture_screenshot(id=session_id)`                                                                                                      |
| **Get Cursor Position** | `instance.computer(action="get_cursor_position").output`                             | Use `move_mouse` with tracking                                                                                                                                    |

***

## Need Help?

----
url: https://www.kernel.sh/docs/browsers/termination
----

Kernel browsers should be terminated after you’re done with them.

Using Playwright/Puppeteer’s method `browser.close()` does not delete the browser. Use one of the methods below to delete the browser.

## [​](#deleting-a-browser-via-session-id)Deleting a browser via session ID

Every browser instance has a `session_id`. You can delete any browser using its session ID:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

await kernel.browsers.deleteByID('htzv5orfit78e1m2biiifpbv');
```

## [​](#automatic-deletion-via-timeout)Automatic deletion via timeout

If you don’t manually delete a browser, it will be automatically deleted after a configurable `timeout` (default 60 seconds). The timeout begins when the browser does not see a CDP or live view connection. You can set a custom timeout of up to 72 hours when creating a browser:

```
import Kernel from '@onkernel/sdk';

const kernel = new Kernel();

const browser = await kernel.browsers.create({ timeout_seconds: 300 });
console.log(browser.session_id);
```

----
url: https://www.kernel.sh/docs/integrations/notte
----

[Notte](https://www.notte.cc/) is an AI agent framework that enables you to build sophisticated browser automation tasks. By integrating with Kernel, you can run Notte agents with cloud-hosted browsers using Chrome DevTools Protocol (CDP).

## [​](#adding-kernel-to-existing-notte-implementations)Adding Kernel to existing Notte implementations

If you already have a Notte implementation, you can easily switch to using Kernel’s cloud browsers by connecting via CDP.

### [​](#1-install-the-kernel-sdk)1. Install the Kernel SDK

```
uv pip install kernel
```

### [​](#2-initialize-kernel-and-create-a-browser)2. Initialize Kernel and create a browser

Import the libraries and create a cloud browser session:

```
from kernel import Kernel
from notte_sdk import NotteClient

# Initialize clients
kernel = Kernel()
notte_client = NotteClient(api_key="your-notte-api-key")

# Create a browser on Kernel
kernel_browser = kernel.browsers.create()
```

### [​](#3-connect-notte-to-kernel’s-cdp-endpoint)3. Connect Notte to Kernel’s CDP endpoint

Use Kernel’s CDP URL to create a Notte session:

```
# Connect Notte to Kernel's browser via CDP
with notte_client.Session(cdp_url=kernel_browser.cdp_ws_url) as session:
    # Create an agent with a task
    agent = notte_client.Agent(session=session, max_steps=10)

    # Run your automation task
    result = agent.run(
        task="extract pricing plans from https://www.notte.cc"
    )
```

### [​](#4-clean-up-the-browser-session)4. Clean up the browser session

After your automation completes, clean up the Kernel browser:

```
kernel.browsers.delete_by_id(kernel_browser.session_id)
```

## [​](#complete-example-script)Complete example script

Here’s a complete, runnable script that demonstrates the full integration:

```
from kernel import Kernel
from notte_sdk import NotteClient
import os
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

def main():
    # Initialize clients
    kernel = Kernel()
    
    notte_api_key = os.getenv("NOTTE_API_KEY")
    if not notte_api_key:
        raise ValueError("NOTTE_API_KEY not found in environment variables")
    
    notte_client = NotteClient(api_key=notte_api_key)

    # Create a headful browser on Kernel
    print("Creating browser session on Kernel...")
    kernel_browser = kernel.browsers.create()
    # print(kernel_browser.browser_live_view_url)

    try:
        # Connect Notte to Kernel's browser via CDP
        print("Connecting Notte to Kernel browser...")
        with notte_client.Session(cdp_url=kernel_browser.cdp_ws_url) as session:
            # Create an agent with a task
            agent = notte_client.Agent(session=session, max_steps=10)

            # Run your automation task
            result = agent.run(
                task="extract pricing plans from https://www.notte.cc"
            )

            print(f"Task completed: {result.answer}")

    except Exception as e:
        print(f"Error during automation: {e}")

    finally:
        # Always clean up the browser session
        kernel.browsers.delete_by_id(kernel_browser.session_id)
        print("Browser session cleaned up")

if __name__ == "__main__":
    main()
```

## [​](#benefits-of-using-kernel-with-notte)Benefits of using Kernel with Notte

* **No local browser management**: Run agents without installing or maintaining browsers locally
* **Scalability**: Launch multiple browser sessions in parallel for concurrent tasks
* **Cloud infrastructure**: Leverage Kernel’s optimized browser infrastructure
* **Stealth mode**: Built-in anti-detection features for web scraping
* **Session control**: Programmatic control over browser lifecycle

## [​](#next-steps)Next steps

* Learn about [creating browsers](https://www.kernel.sh/docs/browsers/create-a-browser) on Kernel
* Check out [live view](https://www.kernel.sh/docs/browsers/live-view) for debugging your automations
* Learn about [stealth mode](https://www.kernel.sh/docs/browsers/bot-detection/stealth) for avoiding detection
* Explore [Profiles](https://www.kernel.sh/docs/auth/profiles) for maintaining browser state across sessions

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/set-file-or-directory-permissionsownership
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.setFilePermissions('id', { mode: '0611', path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

set\_file\_permissions

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.setFilePermissions('id', { mode: '0611', path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-path)

path

string

required

Absolute path whose permissions are to be changed.

Pattern: `^/.*`

[​](#body-mode)

mode

string

required

File mode bits (octal string, e.g. 644).

Pattern: `^[0-7]{3,4}$`

[​](#body-owner)

owner

string

New owner username or UID.

[​](#body-group)

group

string

New group name or GID.

#### Response

Permissions updated

[Delete a directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-directory)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/delete-a-directory)

[Get information about a file or directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/get-information-about-a-file-or-directory)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/get-information-about-a-file-or-directory)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/extensions/download-extension-archive
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.extensions.download('id_or_name');

console.log(response);

const content = await response.blob();
console.log(content);
```

```
"<string>"
```

GET

/

extensions

/

{id\_or\_name}

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.extensions.download('id_or_name');

console.log(response);

const content = await response.blob();
console.log(content);
```

```
"<string>"
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id-or-name)

id\_or\_name

string

required

Extension ID or name

#### Response

Extension ZIP archive

The response is of type `file`.

[Upload a browser extension](https://www.kernel.sh/docs/api-reference/extensions/upload-a-browser-extension)

[Previous](https://www.kernel.sh/docs/api-reference/extensions/upload-a-browser-extension)

[Delete extension by ID or name](https://www.kernel.sh/docs/api-reference/extensions/delete-extension-by-id-or-name)

[Next](https://www.kernel.sh/docs/api-reference/extensions/delete-extension-by-id-or-name)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-replays/start-a-browser-session-replay-recording
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.replays.start('id');

console.log(response.replay_id);
```

```
{
  "replay_id": "<string>",
  "started_at": "2023-11-07T05:31:56Z",
  "finished_at": "2023-11-07T05:31:56Z",
  "replay_view_url": "https://api.onkernel.com/browser/replays?jwt=eyJ0eXAi...&replay_id=7e2c1a9f-1234-4cde-9abc-ffeedd001122"
}
```

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.replays.start('id');

console.log(response.replay_id);
```

```
{
  "replay_id": "<string>",
  "started_at": "2023-11-07T05:31:56Z",
  "finished_at": "2023-11-07T05:31:56Z",
  "replay_view_url": "https://api.onkernel.com/browser/replays?jwt=eyJ0eXAi...&replay_id=7e2c1a9f-1234-4cde-9abc-ffeedd001122"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

application/json

[​](#body-framerate)

framerate

integer

Recording framerate in fps.

Required range

: `1 <= x <= 20`

[​](#body-max-duration-in-seconds)

max\_duration\_in\_seconds

integer

Maximum recording duration in seconds.

Required range

: `x >= 1`

#### Response

Recording started successfully.

Information about a browser replay recording.

[​](#response-replay-id)

replay\_id

string

required

Unique identifier for the replay recording.

[​](#response-started-at-one-of-0)

started\_at

string\<date-time> | null

Timestamp when replay started

[​](#response-finished-at-one-of-0)

finished\_at

string\<date-time> | null

Timestamp when replay finished

[​](#response-replay-view-url)

replay\_view\_url

string

URL for viewing the replay recording.

Example:

`"https://api.onkernel.com/browser/replays?jwt=eyJ0eXAi...&replay_id=7e2c1a9f-1234-4cde-9abc-ffeedd001122"`

[List browser session replays](https://www.kernel.sh/docs/api-reference/browser-replays/list-browser-session-replays)

[Previous](https://www.kernel.sh/docs/api-reference/browser-replays/list-browser-session-replays)

[Download a replay recording](https://www.kernel.sh/docs/api-reference/browser-replays/download-a-replay-recording)

[Next](https://www.kernel.sh/docs/api-reference/browser-replays/download-a-replay-recording)

Ctrl+I

----
url: https://www.kernel.sh/docs/auth/overview
----

Managed Auth creates and maintains authenticated browser sessions for your AI agents. Store credentials once, and Kernel re-authenticates automatically when needed. When you launch Kernel browsers with Managed Auth connections, your agent starts already logged in and ready to go.

## How It Works

## Choose Your Integration

## Why Managed Auth?

The most valuable workflows live behind logins. Managed Auth provides:

## Security

| Feature                    | Description                                        |
| -------------------------- | -------------------------------------------------- |
| **Encrypted credentials**  | Values encrypted with per-organization keys        |
| **No credential exposure** | Never returned in API responses or passed to LLMs  |
| **Encrypted profiles**     | Browser session state encrypted end-to-end         |
| **Isolated execution**     | Each login runs in an isolated browser environment |

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/write-or-create-a-file
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.writeFile('id', fs.createReadStream('path/to/file'), { path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

write\_file

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.writeFile('id', fs.createReadStream('path/to/file'), { path: '/J!' });
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Query Parameters

[​](#parameter-path)

path

string

required

Destination absolute file path.

Pattern: `^/.*`

[​](#parameter-mode)

mode

string

Optional file mode (octal string, e.g. 644). Defaults to 644.

Pattern: `^[0-7]{3,4}$`

#### Body

application/octet-stream

The body is of type `file`.

#### Response

File written successfully

[Read file contents](https://www.kernel.sh/docs/api-reference/browser-filesystem/read-file-contents)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/read-file-contents)

[List files in a directory](https://www.kernel.sh/docs/api-reference/browser-filesystem/list-files-in-a-directory)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/list-files-in-a-directory)

Ctrl+I

----
url: https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-synchronously
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.process.exec('id', { command: 'command' });

console.log(response.duration_ms);
```

```
{
  "exit_code": 123,
  "stdout_b64": "<string>",
  "stderr_b64": "<string>",
  "duration_ms": 123
}
```

exec

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const response = await client.browsers.process.exec('id', { command: 'command' });

console.log(response.duration_ms);
```

```
{
  "exit_code": 123,
  "stdout_b64": "<string>",
  "stderr_b64": "<string>",
  "duration_ms": 123
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

#### Response

Execution result

Result of a synchronous command execution.

[​](#response-exit-code)

exit\_code

integer

Process exit code.

[​](#response-stdout-b64)

stdout\_b64

string

Base64-encoded stdout buffer.

[​](#response-stderr-b64)

stderr\_b64

string

Base64-encoded stderr buffer.

[​](#response-duration-ms)

duration\_ms

integer

Execution duration in milliseconds.

[Upload a zip archive and extract it](https://www.kernel.sh/docs/api-reference/browser-filesystem/upload-a-zip-archive-and-extract-it)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/upload-a-zip-archive-and-extract-it)

[Execute a command asynchronously](https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-asynchronously)

[Next](https://www.kernel.sh/docs/api-reference/browser-processes/execute-a-command-asynchronously)

Ctrl+I

----
url: https://www.kernel.sh/docs/info/unikernels
----

## Introduction

At Kernel, we’ve [pioneered](https://news.ycombinator.com/item?id=43705144) a revolutionary approach to browser automation infrastructure: running Chromium browsers on lightweight unikernels. This architecture represents a significant departure from traditional solutions (warm pools / Kubernetes-orchestrated Docker containers), offering unique capabilities that set our platform apart.

## Technical architecture

Our platform consists of two key components:

1. **Your app code**: we host your app code on isolated unikernel instances, providing isolation and security.
2. **Browser runtime**: each app instance gets its own Chromium browser running on a dedicated Unikraft-based unikernel. Your app code connects to and runs alongside the browser in the cloud.

When you use our [app code](https://www.kernel.sh/docs/apps/deploy) platform, we co-locate your browser automations scripts with the browser environment. This solves a number of issues that remote browsers have, including latency, errors due to unexpected disconnects, and bandwidth issues during data-intensive operations like screenshots.

## Unikernels and browsers

### Unikernels

Unikernels represent a fundamentally different approach to operating system design. Unlike traditional operating systems that include drivers, services, and components for general-purpose computing, unikernels are specialized, single-purpose systems that include only the necessary components to run a specific application.

### Browsers

Browsers are inherently designed to run untrusted code from the internet. To handle this safely, browser architectures incorporate sophisticated isolation mechanisms like sandboxing processes, separating rendering engines from JavaScript execution, and implementing strict security boundaries. This existing security-focused architecture makes browsers exceptionally well-suited for unikernel deployments. While unikernels typically lack internal security boundaries, browsers compensate with their own robust isolation mechanisms. The browser’s multi-process architecture and sandboxing capabilities effectively compensate for this limitation of unikernels. By combining these technologies, we get the best of both worlds. The minimal attack surface and resource efficiency of unikernels, complemented by the browser’s battle-tested security architecture designed specifically for handling untrusted content, creates an ideal environment for secure, efficient browser infrastructure.

## Capabilities

Our browsers-on-unikernels approach unlocks several capabilities unique to our platform:

### Intelligent standby mode

When your app isn’t actively processing network traffic, our browsers automatically go into standby mode. This dramatically reduces resource consumption during idle periods. Unlike traditional “sleep” states, our standby mode preserves the entire browser state while consuming negligible resources, allowing you to maintain long-running sessions without the associated costs.

### Persistent state through snapshots

One of the most powerful features of our approach is the ability to create complete snapshots of the browser’s state when entering standby mode. These snapshots capture everything:

When the browser needs to be reactivated, the Kernel platform restores from these snapshots in milliseconds, allowing you to pick up exactly where you left off.

### Sub-millisecond cold starts

Traditional browser infrastructure takes several seconds to initialize a new browser instance. Our unikernel-based approach achieves cold start times of less than 20 milliseconds. This ultra-fast startup capability makes our platform ideal for event-driven scenarios where rapid response to triggers is essential. Your app can spring to life almost instantly when needed, then return to standby when idle.

## Use cases

Use our platform for anything that requires fast execution, low latency, or long-running browsers:

## Getting started

Sign up for an API key [here](https://dashboard.onkernel.com/sign-up). Our core images are open source on [Github](https://github.com/onkernel/kernel-images).

----
url: https://www.kernel.sh/docs/info/pricing
----

With Kernel, you only pay for what you use and nothing more. You don’t pay for idle time thanks to [Standby Mode](https://www.kernel.sh/docs/browsers/standby), and you’re never charged for proxies.

## Pricing

| Browser type               | Price ($/sec) |
| -------------------------- | ------------- |
| Headless                   | 0.0000166667  |
| Headful                    | 0.0001333336  |
| Headful + GPU acceleration | 0.0008000016  |

> Note: GPU acceleration is only available on headful, on-demand browsers. Standby mode is not supported for GPU-accelerated browsers.

### Pricing calculator

## Managed infrastructure

| Feature                         | Developer (free + usage) | Hobbyist ($30 / mo + usage) | Start-Up ($200 / mo + usage) | Enterprise   |
| ------------------------------- | ------------------------ | --------------------------- | ---------------------------- | ------------ |
| Included credits / mo           | $5                       | $10                         | $50                          | Custom       |
| Extended browser timeouts       | ✅                        | ✅                           | ✅                            | ✅            |
| Browser live view               | ✅                        | ✅                           | ✅                            | ✅            |
| Configurable browser viewports  | ✅                        | ✅                           | ✅                            | ✅            |
| Managed stealth mode            | ✅                        | ✅                           | ✅                            | ✅            |
| Computer controls API           | ✅                        | ✅                           | ✅                            | ✅            |
| Browser replays                 | ❌                        | 7 days                      | 30 days                      | Custom       |
| Browser profiles                | ❌                        | ✅                           | ✅                            | ✅            |
| Managed auth profiles           | ❌                        | ✅                           | ✅                            | ✅            |
| File uploads & downloads        | ❌                        | ✅                           | ✅                            | ✅            |
| Configurable browser extensions | ❌                        | ❌                           | ✅                            | ✅            |
| Configurable & BYO proxies      | ❌                        | ❌                           | ✅                            | ✅            |
| Browser pools                   | ❌                        | ❌                           | ✅                            | ✅            |
| Support                         | Discord                  | Discord                     | Email                        | Shared Slack |
| SOC2 compliance                 | ✅                        | ✅                           | ✅                            | ✅            |
| GPU acceleration                | ❌                        | ❌                           | ✅                            | ✅            |
| HIPAA compliance (BAA)          | ❌                        | ❌                           | ❌                            | ✅            |

> Note: Included monthly credits apply to usage costs only.

## Reserved browsers (browser pools)

With Browser Pools, you pay the standard usage-based price per GB-second while browsers run, plus a small disk space charge when they are idle.

|                                 | Headful    | Headless  |
| ------------------------------- | ---------- | --------- |
| Disk price per GB/hour          | $0.001     | $0.001    |
| Disk allocation per browser     | 4 GB       | 1 GB      |
| Example: 50 browsers idle/month | $144/month | $36/month |

> Note: Disk space charges are waived for Enterprise plan customers.

> Note: GPU acceleration is not available for browser pools.

## Managed Auth

Managed Auth is included on all paid plans with no per-connection fees. Under the hood, it uses browser sessions to log in and keep your sessions fresh—these count toward your browser usage and concurrency like any other browser session. Auth sessions are fast (typically 5-30 seconds each). Kernel monitors session health and re-authenticates automatically when sessions expire—most stay valid for days. For example, keeping 100 auth connections logged in typically costs less than $5/month in browser usage.

## Concurrency limits

| Feature                                                                                 | Developer (free + usage) | Hobbyist ($30 / mo + usage) | Start-Up ($200 / mo + usage) | Enterprise |
| --------------------------------------------------------------------------------------- | ------------------------ | --------------------------- | ---------------------------- | ---------- |
| Reserved browsers ([browser pools](https://www.kernel.sh/docs/browsers/pools/overview)) | 0                        | 0                           | 100                          | Custom     |
| On-demand browsers                                                                      | 5                        | 10                          | 50                           | Custom     |
| App invocations                                                                         | 5                        | 10                          | 50                           | Custom     |
| App invocations (per-app)                                                               | 5                        | 10                          | 20                           | Custom     |
| Managed auth health check interval                                                      | N/A                      | 1 hour minimum              | 20 minutes minimum           | Custom     |

> Note: Browsers in [Standby Mode](https://www.kernel.sh/docs/browsers/standby) count against on-demand concurrency limits.

> Note: Limits are org-wide by default unless stated otherwise. `Managed auth profiles` refer to the number of active auth connections that Kernel maintains using your stored [Credentials](https://www.kernel.sh/docs/auth/credentials) or [1Password connection](https://www.kernel.sh/docs/integrations/1password).

----
url: https://www.kernel.sh/docs/api-reference/browser-filesystem/upload-one-or-more-files
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.upload('id', {
  files: [{ dest_path: '/J!', file: fs.createReadStream('path/to/file') }],
});
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

upload

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

await client.browsers.fs.upload('id', {
  files: [{ dest_path: '/J!', file: fs.createReadStream('path/to/file') }],
});
```

```
{
  "code": "bad_request",
  "message": "Missing required field: app_name",
  "details": [
    {
      "code": "invalid_input",
      "message": "Provided version string is not semver compliant"
    }
  ],
  "inner_error": {
    "code": "invalid_input",
    "message": "Provided version string is not semver compliant"
  }
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Path Parameters

[​](#parameter-id)

id

string

required

Browser session ID

#### Body

multipart/form-data

[​](#body-files)

files

object\[]

required

Show child attributes

#### Response

Files uploaded successfully

[Download a directory as a ZIP archive](https://www.kernel.sh/docs/api-reference/browser-filesystem/download-a-directory-as-a-zip-archive)

[Previous](https://www.kernel.sh/docs/api-reference/browser-filesystem/download-a-directory-as-a-zip-archive)

[Upload a zip archive and extract it](https://www.kernel.sh/docs/api-reference/browser-filesystem/upload-a-zip-archive-and-extract-it)

[Next](https://www.kernel.sh/docs/api-reference/browser-filesystem/upload-a-zip-archive-and-extract-it)

⌘I

----
url: https://www.kernel.sh/docs/api-reference/managed-auth/list-auth-connections
----

```
[
  {
    "id": "ma_abc123xyz",
    "profile_name": "my-netflix-profile",
    "domain": "netflix.com",
    "status": "AUTHENTICATED",
    "save_credentials": true,
    "last_auth_at": "2025-01-15T10:30:00Z",
    "credential": {
      "name": "my-netflix-creds",
      "provider": "my-1p",
      "path": "Personal/Netflix",
      "auto": true
    },
    "can_reauth": true,
    "can_reauth_reason": "has_credential",
    "proxy_id": "<string>",
    "allowed_domains": [
      "login.netflix.com",
      "auth.netflix.com"
    ],
    "post_login_url": "https://www.netflix.com/browse",
    "flow_status": "IN_PROGRESS",
    "flow_step": "AWAITING_INPUT",
    "flow_type": "LOGIN",
    "flow_expires_at": "2025-11-05T20:00:00Z",
    "discovered_fields": [
      {
        "name": "email",
        "type": "email",
        "label": "Email address",
        "selector": "input#email",
        "placeholder": "you@example.com",
        "required": true,
        "linked_mfa_type": "sms"
      }
    ],
    "mfa_options": [
      {
        "type": "sms",
        "label": "Text me a code",
        "target": "***-***-5678",
        "description": "We'll send a 6-digit code to your phone"
      }
    ],
    "pending_sso_buttons": [
      {
        "selector": "xpath=//button[contains(text(), 'Continue with Google')]",
        "provider": "google",
        "label": "Continue with Google"
      }
    ],
    "external_action_message": "Tap 'Yes' on the Google prompt on your phone",
    "website_error": "<string>",
    "sso_provider": "google",
    "error_message": "Invalid password",
    "error_code": "<string>",
    "hosted_url": "https://auth.kernel.com/login/abc123xyz",
    "live_view_url": "https://live.kernel.com/abc123xyz",
    "health_check_interval": 3600
  }
]
```

----
url: https://kernel.sh/docs
----

Kernel is a developer platform that provides Crazy Fast Browsers-as-a-Service for browser automations and web agents. Our API and MCP server allow you to instantly launch browsers in the cloud without managing infrastructure.

## [​](#connect-over-cdp)Connect over CDP

If you are already familiar with browser vendors, you can immediately start using our browsers with `kernel.browsers.create()`. We return a **CDP url** that you can connect any Playwright or Puppeteer automation to.

Install the Kernel SDK with `npm install @onkernel/sdk` or `uv pip install kernel`

```
import Kernel from '@onkernel/sdk';
import { chromium } from 'playwright';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create();
const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url);
```

## [​](#kernel-app-platform)Kernel app platform

If you’re new to building web agents or browser automations, our platform provides a full-featured code execution platform for hosting and invoking your automations in production. Follow our [quickstart guide](https://kernel.sh/docs/quickstart#getting-started) to get started.

## [​](#why-kernel)Why Kernel?

Developers love our platform for its performance, developer experience, and all the other niceties that would otherwise be impractical to homeroll yourself:

* **Serverless browsers** - Connect your web automation to our cloud-based browsers without managing infrastructure
* **Long-lived session states** - Securely authenticate on behalf of your users with [Managed Auth](https://kernel.sh/docs/auth/overview). Browsers can run for up to 72 hours via [timeout configuration](https://kernel.sh/docs/browsers/termination)
* **Live view** - Support human-in-the-loop workflows
* **Replays** - Review past browser sessions as video replays
* **Full isolation** - Kernel browsers are sandboxed in individual, isolated virtual machines
* **Parallel scaling** - Run hundreds or thousands of concurrent browsers at scale
* **Simple, predictable pricing** - We only charge for active browser time

----
url: https://www.kernel.sh/docs/api-reference/deployments/create-a-deployment
----

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const deployment = await client.deployments.create({
  entrypoint_rel_path: 'src/app.py',
  env_vars: { FOO: 'bar' },
  file: fs.createReadStream('path/to/file'),
  region: 'aws.us-east-1a',
  version: '1.0.0',
});

console.log(deployment.id);
```

```
{
  "id": "rr33xuugxj9h0bkf1rdt2bet",
  "status": "queued",
  "region": "aws.us-east-1a",
  "created_at": "2023-11-07T05:31:56Z",
  "status_reason": "Deployment in progress",
  "entrypoint_rel_path": "src/app.py",
  "env_vars": {},
  "updated_at": "2023-11-07T05:31:56Z"
}
```

POST

/

deployments

JavaScript

```
import Kernel from '@onkernel/sdk';

const client = new Kernel({
  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted
});

const deployment = await client.deployments.create({
  entrypoint_rel_path: 'src/app.py',
  env_vars: { FOO: 'bar' },
  file: fs.createReadStream('path/to/file'),
  region: 'aws.us-east-1a',
  version: '1.0.0',
});

console.log(deployment.id);
```

```
{
  "id": "rr33xuugxj9h0bkf1rdt2bet",
  "status": "queued",
  "region": "aws.us-east-1a",
  "created_at": "2023-11-07T05:31:56Z",
  "status_reason": "Deployment in progress",
  "entrypoint_rel_path": "src/app.py",
  "env_vars": {},
  "updated_at": "2023-11-07T05:31:56Z"
}
```

#### Authorizations

[​](#authorization-authorization)

Authorization

string

header

required

Bearer authentication header of the form `Bearer <token>`, where `<token>` is your auth token.

#### Body

multipart/form-data

App deployment data

* Option 1

* Option 2

App deployment request. Provide either file+entrypoint\_rel\_path or source.

[​](#body-one-of-0-file)

file

file

required

ZIP file containing the application source directory

[​](#body-one-of-0-entrypoint-rel-path)

entrypoint\_rel\_path

string

required

Relative path to the entrypoint of the application

Example:

`"src/app.py"`

[​](#body-one-of-0-version)

version

string

default:latest

Version of the application. Can be any string.

Example:

`"1.0.0"`

[​](#body-one-of-0-source)

source

object

Source from which to fetch application code.

Show child attributes

[​](#body-one-of-0-region)

region

string

default:aws.us-east-1a

Region for deployment. Currently we only support "aws.us-east-1a"

Allowed value: `"aws.us-east-1a"`

Example:

`"aws.us-east-1a"`

[​](#body-one-of-0-force)

force

boolean

default:false

Allow overwriting an existing app version

Example:

`false`

[​](#body-one-of-0-env-vars)

env\_vars

object

Map of environment variables to set for the deployed application. Each key-value pair represents an environment variable.

Show child attributes

#### Response

Deployment created successfully

Deployment record information.

[​](#response-id)

id

string

required

Unique identifier for the deployment

Example:

`"rr33xuugxj9h0bkf1rdt2bet"`

[​](#response-status)

status

enum\<string>

required

Current status of the deployment

Available options

:

`queued`,

`in_progress`,

`running`,

`failed`,

`stopped`

Example:

`"queued"`

[​](#response-region)

region

string

required

Deployment region code

Allowed value: `"aws.us-east-1a"`

Example:

`"aws.us-east-1a"`

[​](#response-created-at)

created\_at

string\<date-time>

required

Timestamp when the deployment was created

[​](#response-status-reason)

status\_reason

string

Status reason

Example:

`"Deployment in progress"`

[​](#response-entrypoint-rel-path)

entrypoint\_rel\_path

string

Relative path to the application entrypoint

Example:

`"src/app.py"`

[​](#response-env-vars)

env\_vars

object

Environment variables configured for this deployment

Show child attributes

[​](#response-updated-at-one-of-0)

updated\_at

string\<date-time> | null

Timestamp when the deployment was last updated

[List deployments](https://www.kernel.sh/docs/api-reference/deployments/list-deployments)

[Previous](https://www.kernel.sh/docs/api-reference/deployments/list-deployments)

[Get deployment details](https://www.kernel.sh/docs/api-reference/deployments/get-deployment-details)

[Next](https://www.kernel.sh/docs/api-reference/deployments/get-deployment-details)

Ctrl+I