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

# React SDK

> Embed Rhombus camera streams in React applications with the official SDK, featuring DASH buffered playback and real-time H.264 WebSocket players via WebCodecs.

The official [`@rhombussystems/react`](https://www.npmjs.com/package/@rhombussystems/react) package provides drop-in React components for streaming Rhombus cameras. Two player modes are available:

* **`RhombusBufferedPlayer`** — MPEG-DASH live streaming via Dash.js (buffered, reliable)
* **`RhombusRealtimePlayer`** — Low-latency H.264 over WebSocket via WebCodecs (near real-time)

<Info>
  **Requires React 18+** and a backend endpoint that generates federated session tokens. Your Rhombus API key must never be exposed to the browser.
</Info>

## Install

<CodeGroup>
  ```bash npm theme={null}
  npm install @rhombussystems/react
  ```

  ```bash yarn theme={null}
  yarn add @rhombussystems/react
  ```

  ```bash pnpm theme={null}
  pnpm add @rhombussystems/react
  ```
</CodeGroup>

**Peer dependencies:** `react` and `react-dom` >= 18. The `dashjs` library is included automatically for DASH playback.

## Quick Start

```tsx theme={null}
import { RhombusBufferedPlayer } from "@rhombussystems/react";

export function CameraView() {
  return <RhombusBufferedPlayer cameraUuid="YOUR_CAMERA_UUID" />;
}
```

This renders a DASH-based buffered video player. The component automatically:

1. Requests a federated session token from your backend (`POST /api/federated-token`)
2. Fetches media URIs from the Rhombus API
3. Initializes Dash.js playback

<Warning>
  Your backend **must** implement a `POST /api/federated-token` endpoint (or configure a custom path via the `paths.federatedToken` prop). See [Backend Setup](#backend-setup) below.
</Warning>

## Buffered Player (DASH)

The `RhombusBufferedPlayer` streams MPEG-DASH live video with configurable quality levels.

```tsx theme={null}
import { RhombusBufferedPlayer } from "@rhombussystems/react";

export function BufferedCamera() {
  return (
    <RhombusBufferedPlayer
      cameraUuid="YOUR_CAMERA_UUID"
      bufferedStreamQuality="HIGH"
    />
  );
}
```

### Stream Quality

Control server-side downscaling with the `bufferedStreamQuality` prop:

| Value      | Description                      |
| ---------- | -------------------------------- |
| `"HIGH"`   | Full resolution (default)        |
| `"MEDIUM"` | Medium downscale                 |
| `"LOW"`    | Low resolution, lowest bandwidth |

Changing quality does not re-fetch the manifest or token — the Dash.js `RequestModifier` applies the change on the next segment request.

```tsx theme={null}
import { useState } from "react";
import {
  RhombusBufferedPlayer,
  type RhombusBufferedStreamQuality,
} from "@rhombussystems/react";

export function CameraWithQuality() {
  const [quality, setQuality] = useState<RhombusBufferedStreamQuality>("HIGH");

  return (
    <>
      <select
        value={quality}
        onChange={(e) => setQuality(e.target.value as RhombusBufferedStreamQuality)}
      >
        <option value="HIGH">High</option>
        <option value="MEDIUM">Medium</option>
        <option value="LOW">Low</option>
      </select>
      <RhombusBufferedPlayer
        cameraUuid="YOUR_CAMERA_UUID"
        bufferedStreamQuality={quality}
      />
    </>
  );
}
```

## Realtime Player (WebSocket)

The `RhombusRealtimePlayer` decodes H.264 frames over WebSocket using the browser's WebCodecs API and renders to a `<canvas>`. This provides lower latency than DASH.

```tsx theme={null}
import { RhombusRealtimePlayer } from "@rhombussystems/react";

export function RealtimeCamera() {
  return (
    <RhombusRealtimePlayer
      cameraUuid="YOUR_CAMERA_UUID"
      connectionMode="wan"
    />
  );
}
```

### Connection Modes

| Mode    | Description                                                                                                                                                          |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `"wan"` | Uses the WAN H.264 WebSocket URI with federated token auth appended to the URL                                                                                       |
| `"lan"` | Uses the LAN H.264 WebSocket URI. Federated token auth is appended to the URL the same way as WAN (`x-auth-scheme=federated-token` and `x-auth-ft` query parameters) |

### Stream Quality

| Value  | Description                                                                    |
| ------ | ------------------------------------------------------------------------------ |
| `"HD"` | Full resolution (default)                                                      |
| `"SD"` | Lower resolution via `/wsl` path — changing this prop reconnects the WebSocket |

<Note>
  **Browser compatibility:** WebCodecs with H.264 decoding is supported in Chrome, Edge, and Safari 16.4+. Firefox support is limited.
</Note>

### LAN Mode Considerations

In LAN mode, the SDK appends the federated token to the WebSocket URL as query parameters (`x-auth-scheme=federated-token` and `x-auth-ft`), the same way it does for WAN. This works from any origin, including `localhost`.

The practical requirement for LAN mode is network reachability: the browser must be able to reach the camera/NVR host directly (routing, firewall, and HTTPS-vs-HTTP mixed-content rules all apply). Your Rhombus deployment must also accept the federated-token query parameters on the LAN endpoint.

<Note>
  Earlier SDK versions (pre-1.0) authenticated LAN mode with an `RFT` cookie and an `applyLanAuthCookie` prop. That mechanism was removed in v1.0 — LAN now uses URL query parameters like WAN. If you are following an older guide, update your integration accordingly.
</Note>

## Backend Setup

The SDK requires a server-side endpoint to generate federated session tokens. Your Rhombus API key stays on the server — it is never sent to the browser.

### Token Endpoint

Your backend must expose a POST endpoint (default path: `/api/federated-token`):

<CodeGroup>
  ```javascript Express.js theme={null}
  const express = require("express");
  const app = express();
  app.use(express.json());

  app.post("/api/federated-token", async (req, res) => {
    const response = await fetch(
      "https://api2.rhombussystems.com/api/org/generateFederatedSessionToken",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-auth-scheme": "api-token",
          "x-auth-apikey": process.env.RHOMBUS_API_KEY,
        },
        body: JSON.stringify({
          durationSec: req.body.durationSec || 3600,
          domain: req.headers.origin,
        }),
      }
    );
    const data = await response.json();
    res.json(data);
  });
  ```

  ```python FastAPI theme={null}
  from fastapi import FastAPI, Request
  import httpx, os

  app = FastAPI()

  @app.post("/api/federated-token")
  async def federated_token(request: Request):
      body = await request.json()
      async with httpx.AsyncClient() as client:
          response = await client.post(
              "https://api2.rhombussystems.com/api/org/generateFederatedSessionToken",
              headers={
                  "Content-Type": "application/json",
                  "x-auth-scheme": "api-token",
                  "x-auth-apikey": os.environ["RHOMBUS_API_KEY"],
              },
              json={
                  "durationSec": body.get("durationSec", 3600),
                  "domain": request.headers.get("origin", ""),
              },
          )
      return response.json()
  ```

  ```javascript Next.js API Route theme={null}
  // app/api/federated-token/route.ts
  import { NextResponse } from "next/server";

  export async function POST(request: Request) {
    const body = await request.json();
    const response = await fetch(
      "https://api2.rhombussystems.com/api/org/generateFederatedSessionToken",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-auth-scheme": "api-token",
          "x-auth-apikey": process.env.RHOMBUS_API_KEY!,
        },
        body: JSON.stringify({
          durationSec: body.durationSec || 3600,
          domain: request.headers.get("origin") || "",
        }),
      }
    );
    const data = await response.json();
    return NextResponse.json(data);
  }
  ```
</CodeGroup>

<Warning>
  The `domain` parameter in the token request must match your app's origin. Without it, the browser will get CORS errors when fetching media URIs from `api2.rhombussystems.com`.
</Warning>

### Override Mode (Proxy All Requests)

If you prefer to keep all Rhombus traffic server-side (the browser never talks to Rhombus directly), use `apiOverrideBaseUrl`:

```tsx theme={null}
<RhombusBufferedPlayer
  cameraUuid="YOUR_CAMERA_UUID"
  apiOverrideBaseUrl="https://your-api.example.com"
/>
```

In this mode, your backend must also expose a `POST /api/media-uris` endpoint that proxies to Rhombus's `POST /camera/getMediaUris`.

## Props Reference

### Shared Props

| Prop                    | Type                     | Default                                     | Description                                             |
| ----------------------- | ------------------------ | ------------------------------------------- | ------------------------------------------------------- |
| `cameraUuid`            | `string`                 | required                                    | Camera UUID to stream                                   |
| `apiOverrideBaseUrl`    | `string`                 | —                                           | Route both token and media requests through your server |
| `rhombusApiBaseUrl`     | `string`                 | `https://api2.rhombussystems.com/api`       | Rhombus API base URL (when not using override)          |
| `paths.federatedToken`  | `string`                 | `/api/federated-token`                      | Path to your token endpoint                             |
| `paths.mediaUris`       | `string`                 | `/camera/getMediaUris` or `/api/media-uris` | Path for media URI resolution                           |
| `federatedSessionToken` | `string`                 | —                                           | Skip token fetch; use this token directly               |
| `headers`               | `object`                 | —                                           | Extra headers merged into the token request             |
| `getRequestHeaders`     | `() => object`           | —                                           | Dynamic headers for each request                        |
| `onError`               | `(error: Error) => void` | —                                           | Error callback                                          |

### RhombusBufferedPlayer Props

| Prop                         | Type                              | Default  | Description                              |
| ---------------------------- | --------------------------------- | -------- | ---------------------------------------- |
| `bufferedStreamQuality`      | `"HIGH"` \| `"MEDIUM"` \| `"LOW"` | `"HIGH"` | Server-side downscale level              |
| `applyBufferedStreamQuality` | `boolean`                         | `true`   | Set `false` to disable quality parameter |

### RhombusRealtimePlayer Props

| Prop                    | Type               | Default  | Description                                                          |
| ----------------------- | ------------------ | -------- | -------------------------------------------------------------------- |
| `connectionMode`        | `"wan"` \| `"lan"` | required | WAN or LAN media URIs; both append the token as URL query parameters |
| `realtimeStreamQuality` | `"HD"` \| `"SD"`   | `"HD"`   | Stream resolution; changing reconnects the WebSocket                 |

## Troubleshooting

<AccordionGroup>
  <Accordion title="404 on /api/federated-token">
    Your backend does not have a token endpoint at the expected path. Either implement `POST /api/federated-token` or set the `paths.federatedToken` prop to match your route.
  </Accordion>

  <Accordion title="CORS errors fetching media URIs">
    The federated token was generated without a `domain` matching your app's origin. Pass your app's origin as the `domain` parameter when calling `generateFederatedSessionToken` on your backend.
  </Accordion>

  <Accordion title="Realtime player shows nothing">
    Check browser compatibility — WebCodecs H.264 requires Chrome, Edge, or Safari 16.4+. Check the browser console for `[RhombusRealtimePlayer]` messages.
  </Accordion>

  <Accordion title="LAN mode not authenticating">
    LAN mode appends the federated token to the WebSocket URL as query parameters (the same as WAN), so it works from any origin including `localhost`. If LAN mode fails, confirm the browser can reach the camera/NVR host directly (routing, firewall, and HTTPS-vs-HTTP mixed-content rules), and that your Rhombus deployment accepts federated-token query parameters on the LAN endpoint. If the LAN host is unreachable from the browser, use `connectionMode="wan"` or proxy through your backend.
  </Accordion>
</AccordionGroup>

## Resources

<CardGroup cols={2}>
  <Card title="npm Package" icon="npm" href="https://www.npmjs.com/package/@rhombussystems/react">
    Package details and version history
  </Card>

  <Card title="GitHub Repository" icon="github" href="https://github.com/RhombusSystems/rhombus-react-sdk">
    Source code, examples, and issues
  </Card>

  <Card title="Streaming Video Guide" icon="video" href="/implementations/streaming-video">
    Low-level streaming implementation without the SDK
  </Card>

  <Card title="Video Player Guide" icon="play" href="/implementations/video-player">
    Custom Dash.js player implementation
  </Card>
</CardGroup>
