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

# Bridge protocol

> The raw messages between a mini app and the native shell.

<Info>
  You only need this page if you are not using the SDK, for example in a non-React app. Every message below has a typed wrapper in `@cskn/sdk`.
</Info>

The shell installs `window.cskn.bridge` before your code runs:

```js theme={null}
// to the shell
window.cskn.bridge.postMessage(type, payload);

// from the shell
window.cskn.bridge.addListener((message) => {
  console.log(message.type, message);
});
```

Requests that expect an answer get one with the same type plus `.result`. Several features never answer outside a shell, so check that `window.cskn?.bridge` exists first.

## App → shell

| `type` | Payload | Purpose |
| - | - | - |
| `showHeader` | `value: boolean` | Show or hide the native header |
| `header.set` | `title?, backgroundColor?, textColor?, action?` | Customize the native header |
| `closeApp` | — | Close the app |
| `auth.request` | — | Ask for the current token |
| `platform.get` | — | Ask for OS and host kind |
| `language.get` | — | Ask for the UI language |
| `clipboard.write` | `text` | Write to the clipboard |
| `clipboard.read` | — | Read the clipboard |
| `camera.capture` | `quality?, allowsEditing?` | Take a photo with the system camera |
| `camera.isAvailable` | — | Does the shell have a camera screen? |
| `camera.open` | `mode?, facing?, maxDurationMs?, maxFileSize?, title?, hint?, allowGallery?, audio?, deliver?` | Open the shell's camera screen |
| `qr.scan` | `formats?, title?, hint?, allowGallery?` | Open the QR / barcode reader |
| `imagePicker.open` | `multiple?, quality?` | Open the gallery |
| `statusBar.set` | `style?, backgroundColor?, hidden?` | Style the status bar |
| `navigationBar.set` | `style?, backgroundColor?, hidden?` | Style the Android navigation bar |
| `storage.set` | `key, value` | Save a value |
| `storage.get` | `key` | Read a value |
| `storage.remove` | `key` | Delete a value |
| `storage.keys` | — | List keys |
| `storage.clear` | — | Delete all of this app's values |
| `secureStorage.set` | `key, value` | Save an encrypted string |
| `secureStorage.get` | `key` | Read an encrypted string |
| `secureStorage.remove` | `key` | Delete an encrypted string |
| `notifications.requestPermission` | — | Ask for notification permission |
| `notifications.schedule` | `title, body?, seconds?, repeats?, data?, sound?` | Schedule a local notification |
| `notifications.cancel` | `id` | Cancel one |
| `notifications.cancelAll` | — | Cancel all |
| `notifications.getBadgeCount` | — | Read the badge |
| `notifications.setBadgeCount` | `count` | Set the badge (`0` clears) |
| `notifications.getInbox` | — | Read this app's inbox |
| `notifications.inbox.markRead` | `id?` | Mark one, or all, read |
| `share.open` | `title?, message?, url?` | Share text or a link |
| `share.file` | `uri, mimeType?, dialogTitle?` | Share a device file |
| `share.content` | `data, encoding?, fileName, mimeType?, dialogTitle?` | Share a file the page generated |
| `haptics.impact` | `style?` | Impact feedback |
| `haptics.notification` | `style?` | Outcome feedback |
| `haptics.selection` | — | Selection feedback |
| `biometrics.isAvailable` | — | Check biometrics |
| `biometrics.authenticate` | `promptMessage?, cancelLabel?, fallbackLabel?, disableDeviceFallback?` | Authenticate |
| `passkey.isAvailable` | — | Check passkey support |
| `passkey.create` | `challenge, user?, rp?, pubKeyCredParams?, excludeCredentials?, authenticatorSelection?, attestation?, timeout?` | Register a passkey |
| `passkey.get` | `challenge, allowCredentials?, userVerification?, timeout?` | Sign with a passkey |
| `deeplink.getInitial` | — | Ask for the launch link |
| `deeplink.open` | `slug?, path?, url?, params?` | Open another app, or route in this one |

## Shell → app

| `type` | Fields | Meaning |
| - | - | - |
| `auth` | `token, user?` | Auth token (`null` when signed out). Sent after load and on request. |
| `platform.get.result` | `os, env` | Platform |
| `language` | `language` | UI language, on request and whenever it changes |
| `clipboard.read.result` | `text` | Clipboard text |
| `camera.capture.result` | `asset?, cancelled?, error?` | Photo |
| `camera.isAvailable.result` | `available, video?` | Camera screen support |
| `camera.open.chunk` | `seq, data` | One base64 slice of a recorded video |
| `camera.open.result` | `photo?, video?, chunks?, cancelled?, error?` | Capture finished |
| `qr.scan.result` | `data?, format?, cancelled?, error?` | Scan result |
| `imagePicker.open.result` | `assets?, cancelled?, error?` | Picked images |
| `storage.get.result` | `key, value` | Stored value |
| `storage.keys.result` | `keys` | Key list |
| `secureStorage.get.result` | `key, value` | Encrypted value |
| `notifications.requestPermission.result` | `granted` | Permission |
| `notifications.schedule.result` | `id?, error?` | Scheduled |
| `notifications.getBadgeCount.result` | `count` | Badge |
| `notifications.inbox.result` | `notifications, unreadCount` | Inbox |
| `share.open.result` | `shared` | Share sheet closed |
| `share.file.result` | `shared?, error?` | File shared |
| `share.content.ack` | — | The shell supports `share.content` |
| `share.content.result` | `shared?, error?` | Generated file shared |
| `biometrics.isAvailable.result` | `available, supportsFaceId, supportsFingerprint` | Biometrics |
| `biometrics.authenticate.result` | `success, error?` | Authentication |
| `passkey.isAvailable.result` | `available, autofillAvailable, rpId` | Passkey support |
| `passkey.create.result` | `credential?, cancelled?, error?, message?` | Registration (WebAuthn JSON) |
| `passkey.get.result` | `credential?, cancelled?, error?, message?` | Assertion (WebAuthn JSON) |
| `deeplink.initial` | `deepLink` | Launch link, or `null` |
| `deeplink` | `path, url, params` | A link arrived while the app was open |
| `header.action` | `id?` | Header action tapped |
| `app.insets` | `top, bottom, left, right` | Safe-area insets |
| `keyboard` | `visible, height, duration?` | Keyboard frame (CSS px, ms) |

## Recorded video transfer

A page cannot read the shell's `file://` paths, so a recorded clip is sent as `camera.open.chunk` messages, and `camera.open.result` closes the transfer with the chunk count. Join the `data` fields in `seq` order and decode the base64. Clips over 64 MB are not sent: the result carries `error: 'too_large'` and only `video.uri`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.