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

# Hosted Verify Page: Zero-Code Liveness Integration

> Redirect users to the SpoofSense hosted capture page or embed it in an iframe — no frontend SDK required. Uses the same capture flow as the Web SDK.

The hosted page at `https://app.spoofsense.ai/verify` runs the same capture flow as the Web SDK, served from SpoofSense's origin. Create the session on your backend, then redirect the user to the page or embed it in an iframe — no frontend SDK to install or maintain.

<Note>
  The client token always travels in the **URL fragment** (`#token=…`), never a query parameter. Fragments don't reach servers, so the token never lands in access logs.
</Note>

## Redirect Mode

After creating the session on your backend, build the hosted URL and send the user there:

```javascript theme={null}
const verifyUrl =
  "https://app.spoofsense.ai/verify" +
  `#token=${session.client_token}` +
  `&return_url=${encodeURIComponent("https://yourapp.com/kyc/continue")}`;
res.redirect(verifyUrl);
```

When the user finishes, SpoofSense redirects them back to your `return_url` with the following query parameters:

```text theme={null}
?spoofsense_status=complete&spoofsense_session_id=vs_…
```

`spoofsense_status` can also be `cancelled` or `error`. The query string is a **hint, not proof** — always read the authoritative decision server-side using your secret key.

## Embed (iframe) Mode

Embed the capture flow directly in your page using an iframe. The `allow="camera"` attribute is required, or the browser blocks capture inside the frame:

```html theme={null}
<!-- allow="camera" is required, or the browser blocks capture inside the frame -->
<iframe
  id="spoofsense-verify"
  allow="camera"
  style="width: 100%; max-width: 420px; aspect-ratio: 3 / 4; border: 0"
></iframe>

<script>
  // clientToken comes from YOUR backend. Never mint it in the browser.
  document.getElementById("spoofsense-verify").src =
    "https://app.spoofsense.ai/verify" +
    "#token=" + clientToken +
    "&origin=" + encodeURIComponent(location.origin);

  window.addEventListener("message", (e) => {
    if (e.origin !== "https://app.spoofsense.ai") return; // only trust the hosted page
    if (e.data && e.data.type === "spoofsense:complete") {
      notifyBackend(e.data.verificationSessionId); // backend reads the decision
      // e.data.capturedFrame is the submitted JPEG (Blob), for a local preview.
      preview.src = URL.createObjectURL(e.data.capturedFrame);
    }
    // also emitted: { type: "spoofsense:cancel" } and
    //               { type: "spoofsense:error", code, message }
  });
</script>
```

<Warning>
  Always verify `e.origin` before trusting a message. Treat completion as a hint: the decision only counts when your backend reads `status: "complete"` and `decision: "real"` with the secret key.
</Warning>

## PostMessage Events

The hosted page posts these events to your parent window in iframe mode:

| Message type          | Payload                                                                                   |
| --------------------- | ----------------------------------------------------------------------------------------- |
| `spoofsense:complete` | `verificationSessionId`, `capturedFrame` (Blob), `capturedFrameSha256`, `width`, `height` |
| `spoofsense:cancel`   | —                                                                                         |
| `spoofsense:error`    | `code`, `message` ([standard error codes](/guides/errors))                                |

`capturedFrame` rides the message only because `&origin=` named your page as the target. In redirect mode the image isn't carried in the redirect — your backend retrieves it from the [media endpoint](/verification-sessions/results#retrieving-the-captured-selfie) instead.
