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

# Real-time APIs

> RTStreams offer real-time indexing, transcription, search, and event-based alerts. Convert live video into structured, searchable data.

## Quick Example

<CodeGroup>
  ```python Python theme={null}
  import videodb

  conn = videodb.connect()
  coll = conn.get_collection()
  rtstream = coll.get_rtstream("rts-xxx")

  # Index visuals with a prompt
  scene_index = rtstream.index_visuals(
      prompt="Describe activity and detect unusual behavior",
      batch_config={"type": "time", "value": 5, "frame_count": 2}
  )

  # Create a reusable event
  event_id = conn.create_event(
      event_prompt="Detect when someone enters restricted area",
      label="intrusion_detected"
  )

  # Set up alert
  alert_id = scene_index.create_alert(
      event_id=event_id,
      callback_url="https://your-backend.com/webhooks/alerts"
  )
  ```

  ```javascript Node.js theme={null}
  import { connect } from 'videodb';

  const conn = await connect();
  const coll = await conn.getCollection();
  const rtstream = await coll.getRtstream("rts-xxx");

  // Index visuals with a prompt
  const sceneIndex = await rtstream.indexVisuals({
      prompt: "Describe activity and detect unusual behavior",
      batchConfig: { type: "time", value: 5, frameCount: 2 }
  });

  // Create a reusable event
  const eventId = await conn.createEvent(
      "Detect when someone enters restricted area",
      "intrusion_detected"
  );

  // Set up alert
  const alertId = await sceneIndex.createAlert(
      eventId,
      "https://your-backend.com/webhooks/alerts"
  );
  ```
</CodeGroup>

***

## Visual Indexing

Convert video frames into structured descriptions using prompts.

<CodeGroup>
  ```python Python theme={null}
  scene_index = rtstream.index_visuals(
      prompt="Describe the scene and highlight congestion",
      batch_config={"type": "time", "value": 5, "frame_count": 2},
      name="traffic_monitor",
      ws_connection_id=ws.connection_id  # optional, for real-time events
  )
  ```

  ```javascript Node.js theme={null}
  const sceneIndex = await rtstream.indexVisuals({
      prompt: "Describe the scene and highlight congestion",
      batchConfig: { type: "time", value: 5, frameCount: 2 },
      name: "traffic_monitor",
      wsConnectionId: ws.connectionId  // optional
  });
  ```
</CodeGroup>

### batch\_config Options

| Field         | Type | Description                  |
| :------------ | :--- | :--------------------------- |
| `type`        | str  | Only `"time"` is supported   |
| `value`       | int  | Window size in seconds       |
| `frame_count` | int  | Frames to extract per window |

**Examples:**

```python theme={null}
# Every 5 seconds, extract 2 frames
{"type": "time", "value": 5, "frame_count": 2}

# Every 10 seconds, extract 5 frames
{"type": "time", "value": 10, "frame_count": 5}
```

### Managing Indexes

<CodeGroup>
  ```python Python theme={null}
  # List all indexes
  indexes = rtstream.list_scene_indexes()

  # Get specific index
  scene_index = rtstream.get_scene_index(index_id)

  # Poll scenes
  scenes = scene_index.get_scenes(
      start=0, end=None, page=1, page_size=100
  )
  ```

  ```javascript Node.js theme={null}
  // List all indexes
  const indexes = await rtstream.listSceneIndexes();

  // Get specific index
  const sceneIndex = await rtstream.getSceneIndex(indexId);

  // Poll scenes
  const scenes = await sceneIndex.getScenes({
      start: 0, end: null, page: 1, pageSize: 100
  });
  ```
</CodeGroup>

***

## Audio Indexing

Extract insights from audio tracks:

<CodeGroup>
  ```python Python theme={null}
  audio_index = rtstream.index_audio(
      prompt="Identify key speakers and main topics",
      batch_config={"type": "word", "value": 50}
  )
  ```

  ```javascript Node.js theme={null}
  const audioIndex = await rtstream.indexAudio({
      prompt: "Identify key speakers and main topics",
      batchConfig: { type: "word", value: 50 }
  });
  ```
</CodeGroup>

### Audio batch\_config

| Type         | Value   | Description               |
| :----------- | :------ | :------------------------ |
| `"word"`     | count   | Segment every N words     |
| `"sentence"` | count   | Segment every N sentences |
| `"time"`     | seconds | Segment every N seconds   |

***

## Transcription

Real-time speech-to-text:

<CodeGroup>
  ```python Python theme={null}
  # Start transcription
  rtstream.start_transcript(ws_connection_id=ws.connection_id)

  # Stop transcription
  rtstream.stop_transcript(mode="graceful")

  # Poll transcripts
  transcript = rtstream.get_transcript(
      start=0, page=1, page_size=100
  )
  ```

  ```javascript Node.js theme={null}
  // Start transcription
  await rtstream.startTranscript(ws.connectionId);

  // Stop transcription
  await rtstream.stopTranscript("graceful");

  // Poll transcripts
  const transcript = await rtstream.getTranscript({
      start: 0, page: 1, pageSize: 100
  });
  ```
</CodeGroup>

***

## Search

Query indexed content with natural language:

<CodeGroup>
  ```python Python theme={null}
  results = rtstream.search(
      query="white car moving fast",
      score_threshold=0.5
  )

  for shot in results.shots:
      print(f"Match at {shot.start}: {shot.text}")
      shot.play()  # Opens in browser
  ```

  ```javascript Node.js theme={null}
  const results = await rtstream.search({
      query: "white car moving fast",
      scoreThreshold: 0.5
  });

  for (const shot of results.shots) {
      console.log(`Match at ${shot.start}: ${shot.text}`);
      await shot.play();
  }
  ```
</CodeGroup>

### Search Results

Each shot contains:

| Attribute      | Description           |
| :------------- | :-------------------- |
| `start`        | Start timestamp       |
| `end`          | End timestamp         |
| `text`         | Content description   |
| `search_score` | Relevance score (0-1) |
| `stream_url`   | Playback URL          |

***

## Stream Generation

Use `generate_stream()` to create a playable stream for a time range. You can optionally pass `player_config` to attach metadata to a shareable player URL.

<CodeGroup>
  ```python Python theme={null}
  # Generate stream with player metadata
  player_url = rtstream.generate_stream(
      start=1711000000,
      end=1711003600,
      player_config={
          "title": "Live Feed Recording",
          "description": "Camera 1 - Front entrance",
          "slug": "cam1-front"
      }
  )

  # generate_stream() returns the player_url
  # Both URLs are also stored on the instance
  print(rtstream.player_url)   # Shareable player URL (same as return value)
  print(rtstream.stream_url)   # Raw HLS stream URL (.m3u8)
  ```

  ```javascript Node.js theme={null}
  // Generate stream with player metadata
  const playerUrl = await rtstream.generateStream({
      start: 1711000000,
      end: 1711003600,
      playerConfig: {
          title: "Live Feed Recording",
          description: "Camera 1 - Front entrance",
          slug: "cam1-front"
      }
  });

  // generateStream() returns the playerUrl
  // Both URLs are also stored on the instance
  console.log(rtstream.playerUrl);   // Shareable player URL (same as return value)
  console.log(rtstream.streamUrl);   // Raw HLS stream URL (.m3u8)
  ```
</CodeGroup>

### player\_url vs stream\_url

| URL          | Format                                    | Use case                                             |
| :----------- | :---------------------------------------- | :--------------------------------------------------- |
| `player_url` | `https://console.videodb.io/player?v=...` | Shareable link with built-in player UI               |
| `stream_url` | `https://stream.videodb.io/.../.m3u8`     | Raw HLS stream for custom players (HLS.js, Video.js) |

`generate_stream()` **returns `player_url`** and stores both URLs on the instance. Use `player_url` for sharing and embedding, `stream_url` for custom player integrations.

### player\_config

| Key           | Type | Description                           |
| :------------ | :--- | :------------------------------------ |
| `title`       | str  | Title displayed in the player         |
| `description` | str  | Description for the player page       |
| `slug`        | str  | URL-friendly slug for the player link |

`player_config` is optional. When provided, the player URL includes the metadata for sharing.

### Embed Code

After generating a stream, you can produce embeddable HTML:

<CodeGroup>
  ```python Python theme={null}
  # Generate embed code (requires generate_stream() first)
  rtstream.generate_stream(start=start_ts, end=end_ts)
  embed_html = rtstream.get_embed_code()
  ```

  ```javascript Node.js theme={null}
  // Generate embed code (requires generateStream() first)
  await rtstream.generateStream({ start: startTs, end: endTs });
  const embedHtml = rtstream.getEmbedCode();
  ```
</CodeGroup>

<Note>
  RTStream does **not** support `auto_generate` because `generate_stream()` requires explicit `start` and `end` parameters.
</Note>

***

## Events and Alerts

Events are reusable detection rules. Alerts wire events to indexes for notifications.

### Create Event

<CodeGroup>
  ```python Python theme={null}
  event_id = conn.create_event(
      event_prompt="Detect pedestrians crossing the zebra",
      label="pedestrian_detected"
  )
  ```

  ```javascript Node.js theme={null}
  const eventId = await conn.createEvent(
      "Detect pedestrians crossing the zebra",
      "pedestrian_detected"
  );
  ```
</CodeGroup>

### Create Alert

<CodeGroup>
  ```python Python theme={null}
  alert_id = scene_index.create_alert(
      event_id=event_id,
      callback_url="https://your-backend.com/webhooks/alerts",
      ws_connection_id=ws.connection_id  # optional
  )
  ```

  ```javascript Node.js theme={null}
  const alertId = await sceneIndex.createAlert(
      eventId,
      "https://your-backend.com/webhooks/alerts",
      ws.connectionId  // optional
  );
  ```
</CodeGroup>

### Alert Delivery

| Method    | Latency   | Use Case              |
| :-------- | :-------- | :-------------------- |
| Webhook   | Under 1s  | Server-to-server POST |
| WebSocket | Real-time | Frontend dashboards   |

### Manage Alerts

<CodeGroup>
  ```python Python theme={null}
  # List alerts
  alerts = scene_index.list_alerts()

  # Enable/disable
  scene_index.enable_alert(alert_id)
  scene_index.disable_alert(alert_id)
  ```

  ```javascript Node.js theme={null}
  // List alerts
  const alerts = await sceneIndex.listAlerts();

  // Enable/disable
  await sceneIndex.enableAlert(alertId);
  await sceneIndex.disableAlert(alertId);
  ```
</CodeGroup>

***

## WebSocket Events

Receive real-time events by passing `ws_connection_id`:

<CodeGroup>
  ```python Python theme={null}
  ws = conn.connect_websocket()
  await ws.connect()

  # Pass ws_connection_id to methods
  rtstream.start_transcript(ws_connection_id=ws.connection_id)

  # Receive events
  async for ev in ws.stream():
      channel = ev.get("channel")

      if channel == "transcript":
          print(f"TRANSCRIPT: {ev['data']['text']}")
      elif channel == "scene_index":
          print(f"SCENE: {ev['data']['text']}")
      elif channel == "alert":
          print(f"ALERT: {ev['data']}")
  ```

  ```javascript Node.js theme={null}
  const ws = conn.connectWebsocket();
  await ws.connect();

  // Pass wsConnectionId to methods
  await rtstream.startTranscript(ws.connectionId);

  // Receive events
  for await (const ev of ws.stream()) {
      const channel = ev.channel;

      if (channel === "transcript") {
          console.log(`TRANSCRIPT: ${ev.data.text}`);
      } else if (channel === "scene_index") {
          console.log(`SCENE: ${ev.data.text}`);
      } else if (channel === "alert") {
          console.log(`ALERT: ${ev.data}`);
      }
  }
  ```
</CodeGroup>

### Event Channels

| Channel       | Source               | Content                  |
| :------------ | :------------------- | :----------------------- |
| `transcript`  | `start_transcript()` | Real-time speech-to-text |
| `scene_index` | `index_visuals()`    | Visual analysis          |
| `audio_index` | `index_audio()`      | Audio analysis           |
| `alert`       | `create_alert()`     | Alert notifications      |

***

## Next Steps

<CardGroup cols={2}>
  <Card icon="link" title="Stream Lifecycle" href="/pages/ingest/live-streams/stream-lifecycle">
    Start, stop, and reconnect patterns
  </Card>

  <Card icon="link" title="RTSP Ingest" href="/pages/ingest/live-streams/rtsp-ingest">
    Connect RTSP sources
  </Card>
</CardGroup>
