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

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

<CodeGroup>
  ```typescript Typescript/Javascript theme={null}
  import Kernel from '@onkernel/sdk';

  const kernel = new Kernel();

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

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

  kernel = Kernel()

  browser = kernel.browsers.create()
  print(browser.browser_live_view_url)
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"fmt"

  	"github.com/kernel/kernel-go-sdk"
  )

  func main() {
  	ctx := context.Background()
  	client := kernel.NewClient()

  	browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
  	if err != nil {
  		panic(err)
  	}

  	fmt.Println(browser.BrowserLiveViewURL)
  }
  ```
</CodeGroup>

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

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

If your environment restricts outbound traffic, allow the [Live View domains and ports](/info/network-access#required-destinations) before you embed it.

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

<Info>
  Embedded third-party iframes like live view must have focus to receive keyboard events. On Safari, focus requires a user-initiated event — calling `.focus()` on the iframe element within a user-initiated event handler is recommended.

  To enable clipboard sharing, add `allow="autoplay; clipboard-read; clipboard-write"` to the iframe element.

  If your application uses a **Content Security Policy (CSP)**, you must add the following directives to allow the live view iframe and its WebSocket connection. See [Network access](/info/network-access#content-security-policy) for the complete firewall and CSP requirements.

  ```
  frame-src https://*.onkernel.com:8443
            https://*.kernel.sh:8443;
  connect-src https://*.onkernel.com:8443
              wss://*.onkernel.com:8443
              https://*.kernel.sh:8443
              wss://*.kernel.sh:8443;
  ```
</Info>

## Parent frame events

When the live view is embedded in an iframe, the client posts messages to the parent window as the connection and playback state change, and accepts one message back. Use them to tell a working viewer apart from one that never starts.

### Sent to the parent

| Event                       | Payload                                                                           | Meaning                                                             |
| --------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `KERNEL_CONNECTED`          | `connected`, `capabilities` (recent images only)                                  | Signaling is established. Frames are not necessarily rendering yet. |
| `KERNEL_PLAYING`            | `playing: true`                                                                   | Video frames are rendering.                                         |
| `KERNEL_PAUSED`             | `playing: false`                                                                  | Playback has stopped.                                               |
| `KERNEL_CONNECTION_TIMEOUT` | `reason`, `iceConnectionState`, `connectionState`, `signalingState`, `socketOpen` | The client's connection watchdog expired. Useful for diagnostics.   |
| `KERNEL_READ_ONLY_CHANGED`  | `readOnly`, `requestId`                                                           | Acknowledges a `KERNEL_SET_READ_ONLY` request.                      |

### Accepted from the parent

| Event                  | Payload                                              | Effect                                                                                            |
| ---------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `KERNEL_SET_READ_ONLY` | `readOnly` (boolean), `requestId` (string, optional) | Toggles interactivity without reloading the iframe. Acknowledged with `KERNEL_READ_ONLY_CHANGED`. |

<Info>
  `KERNEL_CONNECTION_TIMEOUT`, `KERNEL_READ_ONLY_CHANGED` and `KERNEL_SET_READ_ONLY` require a recent browser image. `KERNEL_CONNECTED`, `KERNEL_PLAYING` and `KERNEL_PAUSED` are available on all current images, but `capabilities` is sent only by recent ones — older images post `{ type: 'KERNEL_CONNECTED', connected: true }`, so treat a missing `capabilities` as unknown rather than unsupported.

  Messages are exchanged with the parent origin derived from `document.referrer`. If the referrer is unavailable — for example under a restrictive `Referrer-Policy` — the client cannot resolve your origin and will reject `KERNEL_SET_READ_ONLY`.
</Info>

### Detecting a viewer that never starts

Gate on `KERNEL_PLAYING`. It fires only once frames actually arrive, so it is the one signal that distinguishes a working viewer from one that is still connecting or has silently failed. Start a timer when you mount the iframe and remount if `KERNEL_PLAYING` has not arrived:

```typescript Typescript/Javascript theme={null}
const iframe = document.querySelector('#kernel-live-view');
const src = iframe.src;
const liveViewOrigin = new URL(src).origin;

let attempts = 0;
let watchdog;

function arm() {
  clearTimeout(watchdog);
  watchdog = setTimeout(() => {
    if (attempts++ >= 2) return showFallback();
    iframe.src = 'about:blank';
    iframe.src = src;
    arm();
  }, 15000);
}

window.addEventListener('message', (event) => {
  if (event.origin !== liveViewOrigin) return;
  if (event.data?.type === 'KERNEL_PLAYING') clearTimeout(watchdog);
  if (event.data?.type === 'KERNEL_PAUSED') arm();
});

arm();
```

Do not gate on `KERNEL_CONNECTION_TIMEOUT` alone. The watchdog behind it is cleared once negotiation begins, so a connection that stalls after that point never emits it. Log it alongside `KERNEL_PLAYING` to capture the connection state at the moment things stalled.

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

<Info>
  Kiosk mode triggers a Chromium restart, which can take several seconds. Use [browser pools](/browsers/pools) to access kiosk mode browsers faster.
</Info>

<CodeGroup>
  ```typescript Typescript/Javascript theme={null}
  const browser = await kernel.browsers.create({
      kiosk_mode: true
  });
  ```

  ```python Python theme={null}
  kernel_browser = kernel.browsers.create(
      kiosk_mode=True
  )
  ```

  ```go Go theme={null}
  browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
  	KioskMode: kernel.Bool(true),
  })
  if err != nil {
  	panic(err)
  }
  _ = browser
  ```
</CodeGroup>

## URL lifetime

`browser_live_view_url` becomes invalid once the browser is [deleted](/browsers/termination) manually or via timeout.
