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

# Camera Integration

> Add camera-based heart rate to a browser app with the Elata rPPG Web SDK.

<Note>
  Use this guide when you want live camera-based heart rate in a browser app. Start with the quick path first. Move to the manual pipeline only if you need lower-level control.
</Note>

## What this guide covers

This guide shows how to:

* capture webcam frames in the browser
* detect a face and extract a face region
* feed samples into the rPPG processor
* read live BPM and signal quality
* improve estimates with Muse PPG when available

## Before you start

<CodeGroup>
  ```bash pnpm theme={null}
  pnpm add @elata-biosciences/rppg-web
  ```

  ```bash npm theme={null}
  npm install @elata-biosciences/rppg-web
  ```
</CodeGroup>

* `@elata-biosciences/rppg-web` installed
* Browser with camera access (`getUserMedia`) and WebAssembly support
* HTTPS or localhost for development

You need:

* `@elata-biosciences/rppg-web`
* a browser with camera access and WebAssembly support
* `https://` or `localhost`

<Info>
  rPPG works best when the face is well lit, mostly still, and fully visible in frame.
</Info>

## Choose a starting point

<Columns cols={2}>
  <Card title="Start from a demo" href="/sdk/create-elata-demo">
    Scaffold a working browser app if you want the fastest path to a reference implementation.
  </Card>

  <Card title="rPPG Web getting started" href="/sdk/rppg-web/getting-started">
    Learn the package entry points and the higher-level browser API.
  </Card>

  <Card title="Frame sources" href="/sdk/rppg-web/frame-sources">
    See the lower-level camera and face-detection primitives used in this guide.
  </Card>

  <Card title="Calibration and fusion" href="/sdk/rppg-web/calibration">
    Add Muse-based calibration when you want stronger estimates.
  </Card>
</Columns>

## Quick integration

For most apps, use `DemoRunner`. It handles frame capture, face detection, ROI extraction, and processing in one flow.

<Tabs>
  <Tab title="pnpm">
    ```bash theme={null}
    pnpm add @elata-biosciences/rppg-web
    ```
  </Tab>

  <Tab title="npm">
    ```bash theme={null}
    npm install @elata-biosciences/rppg-web
    ```
  </Tab>
</Tabs>

```ts theme={null}
import {
  RppgProcessor,
  MediaPipeFrameSource,
  DemoRunner,
} from "@elata-biosciences/rppg-web";

const source = new MediaPipeFrameSource();
const processor = new RppgProcessor("wasm", 30);

const runner = new DemoRunner(source, processor, {
  useSkinMask: true,
  onStats: () => {
    const metrics = processor.getMetrics();

    document.getElementById("bpm")!.textContent =
      metrics.bpm?.toFixed(0) ?? "--";

    document.getElementById("quality")!.textContent =
      `${((metrics.quality ?? 0) * 100).toFixed(0)}%`;
  },
});

await runner.start();
```

<Tip>
  Show BPM only when signal quality is above your app's threshold. A threshold around `0.5` is a practical starting point.
</Tip>

## Manual pipeline

Use the manual path when you want tighter control over face tracking, sampling, or how your app renders intermediate results.

<Steps>
  <Step title="Load the face model and create a frame source">
    ```ts theme={null}
    import {
      MediaPipeFaceFrameSource,
      loadFaceMesh,
    } from "@elata-biosciences/rppg-web";

    const faceMesh = await loadFaceMesh();
    const source = new MediaPipeFaceFrameSource(faceMesh);
    ```
  </Step>

  <Step title="Create the processor">
    ```ts theme={null}
    import { RppgProcessor } from "@elata-biosciences/rppg-web";

    const processor = new RppgProcessor("wasm", 30, 10);
    ```

    The third argument sets a 10-second analysis window.
  </Step>

  <Step title="Push samples from the face ROI">
    ```ts theme={null}
    import { averageGreenInROI } from "@elata-biosciences/rppg-web";

    source.onFrame = (frame) => {
      if (!frame.roi) return;

      const { x, y, w, h } = frame.roi;
      const green = averageGreenInROI(frame, x, y, w, h);

      processor.pushSample(
        frame.timestampMs ?? performance.now(),
        green,
      );
    };
    ```
  </Step>

  <Step title="Start the camera and read metrics">
    ```ts theme={null}
    await source.start();

    setInterval(() => {
      const metrics = processor.getMetrics();
      console.log("BPM:", metrics.bpm, "quality:", metrics.quality);
    }, 1000);
    ```
  </Step>
</Steps>

## Add Muse calibration

If a Muse device is available, you can use its PPG as a reference signal to improve camera-based estimates.

```ts theme={null}
import { RppgProcessor } from "@elata-biosciences/rppg-web";

const processor = new RppgProcessor("wasm", 30);

processor.updateMuseMetrics(museBpm, 0.9, performance.now());
```

<Info>
  For a fuller fusion workflow, including `MuseFusionCalibrator` and calibration models, continue to [/sdk/rppg-web/calibration](/sdk/rppg-web/calibration).
</Info>

## Quality checklist

Use this checklist before debugging the pipeline:

* keep lighting even across the face
* reduce head movement
* wait 5 to 10 seconds before trusting early BPM output
* make sure a face ROI is actually being detected
* enable `useSkinMask` when you use `DemoRunner`

## Where to go next

<Columns cols={2}>
  <Card title="rPPG Web getting started" href="/sdk/rppg-web/getting-started">
    Learn the package surface and the higher-level browser session API.
  </Card>

  <Card title="Frame sources" href="/sdk/rppg-web/frame-sources">
    Understand the camera and face-detection primitives in more detail.
  </Card>

  <Card title="Calibration and fusion" href="/sdk/rppg-web/calibration">
    Improve estimates with Muse-based calibration and multi-source fusion.
  </Card>

  <Card title="create-elata-demo" href="/sdk/create-elata-demo">
    Start from a working reference app if you want a faster onboarding path.
  </Card>
</Columns>
