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

# Web SDK: Browser Camera Capture for Live Verification

> Add face liveness capture to any website using the SpoofSense React component or vanilla JS SDK. Captures from the live camera with injection protection.

The Web SDK renders a camera view, guides the user, captures a frame from the **live stream** (never a file upload), and submits it with anti-injection signals. Your page receives a callback with the session id — the decision stays server-side where only your backend can read it.

Requires a browser with camera access over HTTPS. You need a `clientToken` (`sst_…`) minted by [your backend](/verification-sessions/overview) before mounting the SDK.

## Installation and Usage

<Tabs>
  <Tab title="React">
    ```bash theme={null}
    npm install @spoofsense/react
    ```

    ```tsx theme={null}
    import { SpoofSenseCapture } from "@spoofsense/react";

    function VerifyStep({ clientToken }: { clientToken: string }) {
      return (
        <SpoofSenseCapture
          sessionToken={clientToken}
          onComplete={({ verificationSessionId, capturedFrame }) => {
            // capturedFrame is the submitted JPEG (Blob) — fine for a local
            // preview or your own upload. For the authoritative copy, your
            // backend fetches the session media.
            setPreview(URL.createObjectURL(capturedFrame));
            // Tell your backend to fetch the result for this session.
            notifyBackend(verificationSessionId);
          }}
          onError={(e) => console.warn(e.code, e.message)}
        />
      );
    }
    ```
  </Tab>

  <Tab title="Vanilla JS">
    ```bash theme={null}
    npm install @spoofsense/web-sdk
    ```

    ```javascript theme={null}
    import * as SpoofSense from "@spoofsense/web-sdk";

    const handle = SpoofSense.mount({
      sessionToken: clientToken,   // the sst_… token from your backend
      container: "#verify",        // element or selector
      onComplete: ({ verificationSessionId, capturedFrame, capturedFrameSha256 }) => {
        showPreview(URL.createObjectURL(capturedFrame)); // the submitted JPEG
        notifyBackend(verificationSessionId);
      },
      onError: (e) => console.warn(e.code, e.message),
    });
    // call handle.unmount() when done
    ```
  </Tab>

  <Tab title="CDN Script Tag">
    ```html theme={null}
    <div id="verify"></div>
    <script src="https://cdn.jsdelivr.net/npm/@spoofsense/web-sdk/dist/spoofsense.min.js"></script>
    <script>
      SpoofSense.mount({
        sessionToken: CLIENT_TOKEN, // the sst_… token from your backend
        container: "#verify",
        onComplete: function (r) {
          showPreview(URL.createObjectURL(r.capturedFrame));
          notifyBackend(r.verificationSessionId);
        },
        onError: function (e) { console.warn(e.code, e.message); },
      });
    </script>
    ```
  </Tab>
</Tabs>

## The Completion Callback

| Field                   | Description                                                                                           |
| ----------------------- | ----------------------------------------------------------------------------------------------------- |
| `verificationSessionId` | The `vs_…` id — send this to your backend so it can [read the result](/verification-sessions/results) |
| `capturedFrame`         | The exact JPEG that was submitted, as a `Blob` — for a local preview or your own storage              |
| `capturedFrameSha256`   | Hash of those bytes; matches `media.sha256` on the server-side read                                   |

`onError` receives `{ code, message }` using the [standard error codes](/guides/errors) — for example, `SESSION_EXPIRED` means you should mint a fresh session. Retryable `422` errors are handled inside the SDK's built-in retake flow and never surface as `onError` calls.

## Behavior Notes

* The SDK calls `GET /v1/verification_sessions/session_info` at mount to validate the token and fetch the session nonce **before** opening the camera — an expired or already-used session fails fast with no camera prompt.
* Retakes for user-fixable problems (no face detected, blur, backlight) are built in, up to the session's 3-attempt limit.
* The SDK never exposes scores or decisions to the page. Always verify the outcome server-side.

<Note>
  Prefer zero frontend code? Use the [hosted page](/verification-sessions/hosted) — it runs the same capture flow, served from SpoofSense's origin, with no SDK to install.
</Note>
