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

# Privacy Controls

> Consent patterns, permission handling, and privacy-first capture

Desktop capture handles sensitive data. Nothing records without explicit user consent. This page covers permission patterns, storage controls, and privacy-first design.

<Note>
  Desktop capture currently supports **macOS** and **Windows**.
</Note>

## Quick Example

<CodeGroup>
  ```python Python theme={null}
  from videodb.capture import CaptureClient

  client = CaptureClient(client_token=token)

  # Request explicit permissions (OS dialogs appear)
  await client.request_permission("microphone")
  await client.request_permission("screen_capture")

  # User must grant permission before capture can start
  channels = await client.list_channels()
  ```

  ```javascript Node.js theme={null}
  import { CaptureClient } from 'videodb/capture';

  const client = new CaptureClient({ sessionToken: token });

  // Request explicit permissions (OS dialogs appear)
  await client.requestPermission('microphone');
  await client.requestPermission('screen-capture');

  // User must grant permission before capture can start
  const channels = await client.listChannels();
  ```
</CodeGroup>

***

## Trust Model

### Two-Component Architecture

Security is built into the architecture:

| Component | Has API Key | Can See Media |
| :- | :- | :- |
| Backend | Yes | No (receives events only) |
| Desktop Client | No (uses token) | Yes (captures locally) |

* **API key never leaves your backend**
* **Desktop client uses short-lived tokens** (10-15 min expiry recommended)
* **Compromised tokens have limited blast radius**

### Token Pattern

<CodeGroup>
  ```python Python theme={null}
  # Backend (holds API key)
  conn = videodb.connect()  # Uses VIDEO_DB_API_KEY

  # Generate short-lived token for client
  token = conn.generate_client_token(expires_in=600)  # 10 minutes

  # Send token to desktop app (never send API key)
  ```

  ```javascript Node.js theme={null}
  // Backend (holds API key)
  const conn = connect();  // Uses VIDEO_DB_API_KEY

  // Generate short-lived token for client
  const token = await conn.generateClientToken(600);  // 10 minutes

  // Send token to desktop app (never send API key)
  ```
</CodeGroup>

***

## Permission Handling

### Request Before Capture

<CodeGroup>
  ```python Python theme={null}
  # Each permission triggers an OS dialog
  await client.request_permission("microphone")
  await client.request_permission("screen_capture")
  ```

  ```javascript Node.js theme={null}
  // Each permission triggers an OS dialog
  await client.requestPermission('microphone');
  await client.requestPermission('screen-capture');
  ```
</CodeGroup>

### Required UX Elements

<Warning>
  Your desktop client must include:

  * **Recording indicator** - Visual cue that capture is active
  * **Pause button** - Let users temporarily stop
  * **Stop button** - Let users end the session
</Warning>

***

## Storage Control

### Ephemeral Mode

Process in real-time without persisting media:

<CodeGroup>
  ```python Python theme={null}
  channels = await client.list_channels()
  selected = [
      channel
      for channel in (
          channels.mics.default,
          channels.displays.default,
          channels.system_audio.default,
      )
      if channel
  ]
  for channel in selected:
      channel.store = False

  await client.start_session(
      capture_session_id=cap_id,
      channels=selected,
  )
  ```

  ```javascript Node.js theme={null}
  const channels = await client.listChannels();
  const selectedChannels = [
      channels.mics.default,
      channels.displays.default,
      channels.systemAudio.default,
  ]
      .filter(Boolean)
      .map(channel => ({ channelId: channel.id, type: channel.type, store: false }));

  await client.startSession({
      sessionId: capId,
      channels: selectedChannels,
  });
  ```
</CodeGroup>

**Use ephemeral mode when:**

* Processing sensitive content
* Storage isn't needed
* Privacy regulations require it
* Building real-time assistants only

### Selective Storage

Store only what you need:

<CodeGroup>
  ```python Python theme={null}
  channels = await client.list_channels()
  mic = channels.mics.default
  display = channels.displays.default
  system_audio = channels.system_audio.default

  if mic:
      mic.store = True
  if display:
      display.store = False
  if system_audio:
      system_audio.store = True

  selected = [channel for channel in (mic, display, system_audio) if channel]
  await client.start_session(
      capture_session_id=cap_id,
      channels=selected,
  )
  ```

  ```javascript Node.js theme={null}
  const channels = await client.listChannels();
  const mic = channels.mics.default;
  const display = channels.displays.default;
  const systemAudio = channels.systemAudio.default;
  const selectedChannels = [
      [mic, true],
      [display, false],
      [systemAudio, true],
  ]
      .filter(([channel]) => Boolean(channel))
      .map(([channel, store]) => ({ channelId: channel.id, type: channel.type, store }));

  await client.startSession({
      sessionId: capId,
      channels: selectedChannels,
  });
  ```
</CodeGroup>

***

## Data Retention

### Default Behavior

* Tell users which selected channels may be stored and for how long.
* Define a retention schedule and access policy in your product before capture starts.
* Keep the records needed to honor consent, access, and deletion requests.

### Data Subject Requests

Provide authenticated ways for people to request access to or deletion of their data, and document how your application maps those requests to its stored media. Coordinate the provider-side lifecycle with your retention process.

<Note>
  Python supports `list_capture_sessions(collection_id="default", status=None)`. It does not support an `end_user_id` filter or `CaptureSession.delete()`, so keep per-user mapping and deletion orchestration in your application until a supported lifecycle API is available.
</Note>

***

## Compliance Patterns

### GDPR

* Document processing purposes and the data captured for each purpose.
* Provide a clear process for access and deletion requests.
* Minimize collection by selecting only the channels your workflow requires.

### HIPAA and Sensitive Data

* Apply strict access controls and audit access to sensitive captures.
* Minimize captured and stored data, and follow your organization's applicable compliance program.
* Consult your legal, privacy, and security teams for the deployment requirements that apply to your use case.

### General Best Practices

| Practice | Implementation |
| :- | :- |
| Never expose API keys | Use client tokens |
| Default to ephemeral | Only persist when needed |
| Short token lifetimes | 10-15 minutes |
| Support data requests | Define an authenticated application workflow |
| Get consent | Permission dialogs before capture |
| Show indicators | Recording visible to user |

***

## Summary

<Warning>
  **Key principles:**

  * Nothing records without explicit user permission
  * Storage is optional per-channel (`store: false`)
  * Visible recording indicators are required
  * API key never leaves backend
  * Tokens are short-lived and limited scope
</Warning>

***

## Next Steps

<CardGroup cols={2}>
  <Card icon="camera" title="Capture Overview" href="/pages/ingest/capture-sdks/overview">
    Architecture and quickstart
  </Card>

  <Card icon="zap" title="Real-time Context" href="/pages/ingest/capture-sdks/realtime-context">
    Events you receive
  </Card>
</CardGroup>


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