> ## Documentation Index
> Fetch the complete documentation index at: https://tbd-6fc993ce-hypeship-docker-sandboxes-integration.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Playwright Execution

> Execute Playwright code in the same VM as your browser

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](/apps)**.

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

<CodeGroup>
  ```typescript Typescript/Javascript theme={null}
  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"
  ```

  ```python Python theme={null}
  from kernel import Kernel

  kernel = Kernel()

  # Create a browser
  kernel_browser = kernel.browsers.create()

  # Execute Playwright code
  response = kernel.browsers.playwright.execute(
      id=kernel_browser.session_id,
      code="""
          await page.goto('https://example.com')
          return await page.title()
      """
  )

  print(response.result)  # "Example Domain"
  ```

  ```bash CLI theme={null}
  kernel browsers playwright execute <session_id> 'await page.goto("https://www.onkernel.com"); return page.title();'
  ```
</CodeGroup>

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

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

<CodeGroup>
  ```typescript Typescript/Javascript theme={null}
  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" }
  ```

  ```python Python theme={null}
  response = kernel.browsers.playwright.execute(
      id=session_id,
      code="""
          await page.goto('https://example.com')
          title = await page.title()
          url = page.url()
          return {'title': title, 'url': url}
      """
  )

  print(response.result)  # {'title': 'Example Domain', 'url': 'https://example.com'}
  ```
</CodeGroup>

## Timeout configuration

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

<CodeGroup>
  ```typescript Typescript/Javascript theme={null}
  const response = await kernel.browsers.playwright.execute(
    sessionId,
    {
      code: `
        await page.goto('https://example.com');
        return await page.title();
      `,
      timeout_sec: 120
    }
  );
  ```

  ```python Python theme={null}
  response = kernel.browsers.playwright.execute(
      id=session_id,
      code="""
          await page.goto('https://example.com')
          return await page.title()
      """,
      timeout_sec=120
  )
  ```
</CodeGroup>

## Error handling

The response includes error information if execution fails:

<CodeGroup>
  ```typescript Typescript/Javascript theme={null}
  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);
  }
  ```

  ```python Python theme={null}
  response = kernel.browsers.playwright.execute(
      id=session_id,
      code="""
          await page.goto('https://invalid-url')
          return await page.title()
      """
  )

  if not response.success:
      print('Error:', response.error)
      print('Stderr:', response.stderr)
  ```
</CodeGroup>

## Use cases

### Web scraping

Extract data from multiple pages without CDP overhead:

```typescript theme={null}
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

Fill and submit forms quickly:

```typescript theme={null}
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

Run quick checks against your browser state:

```typescript theme={null}
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

Capture screenshots using Playwright's native screenshot API:

```typescript theme={null}
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);
```

<Note>
  For OS-level screenshots using coordinates and regions, see [Computer Controls](/browsers/computer-controls#take-screenshots).
</Note>

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

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