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

# IDV Flow

> Camera-based identity document verification with automatic capture, processing, and result handling.

## Overview

The IDV (Identity Verification) flow uses camera-based document capture powered by Incode. The SDK handles the entire capture experience — the user points their camera at an ID document and the SDK automatically detects, captures, and processes it. This is the simplest embedded flow to implement.

**Modules used:** [`idv`](/docs/sdk-reference/idv-module), [`form`](/docs/sdk-reference/form-module) (WELCOME, CONSENT, LOADING screens)

<Callout icon="star" color="#3DD892" iconType="regular">
  Instead of building from scratch, fork an existing flow from the [public sample codes](https://github.com/FrankieOne/frontend-onesdk-public-sample-codes/).
</Callout>

## Flow Diagram

<Steps>
  <Step title="Welcome Screen">
    Initial greeting and introduction to the verification process.
  </Step>

  <Step title="Consent Screen">
    Capture user consent for data processing.
  </Step>

  <Step title="IDV Capture">
    The SDK renders camera capture UI for document scanning.
  </Step>

  <Step title="Processing">
    The SDK processes the captured document and runs verification checks.
  </Step>

  <Step title="Result">
    Your application receives the verification result and displays the outcome.
  </Step>
</Steps>

## Full Implementation

<Tabs>
  <Tab title="Vanilla HTML/JS">
    ```html theme={null}
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>OneSDK IDV Flow</title>
        <script src="https://assets.frankiefinancial.io/one-sdk/v1/oneSdk.umd.js"></script>
        <style>
          body { margin: 0; font-family: sans-serif; background: #fff; }
          #onesdk-wrapper { position: relative; width: 100%; height: 100vh; }
          #onesdk-container { width: 100%; height: 100%; }
          #loading-overlay {
            position: absolute; top: 0; left: 0; width: 100%; height: 100%;
            z-index: 10; background: #fff;
          }
        </style>
      </head>
      <body>
        <div id="onesdk-wrapper">
          <div id="onesdk-container"></div>
          <div id="loading-overlay"></div>
        </div>

        <script>
          async function startOneSDK() {
            try {
              // 1. Generate session token (move to your backend in production)
              const tokenResponse = await fetch(
                "https://backend.kycaml.uat.frankiefinancial.io/auth/v2/machine-session",
                {
                  method: "POST",
                  headers: {
                    authorization: "machine " + btoa("<CUSTOMER_ID>:<CUSTOMER_CHILD_ID>:<API_KEY>"),
                    "Content-Type": "application/json",
                  },
                  body: JSON.stringify({
                    permissions: {
                      preset: "one-sdk",
                      reference: "idv-" + Date.now(),
                    },
                  }),
                }
              );
              const session = await tokenResponse.json();

              // 2. Initialize OneSDK
              const oneSdk = await OneSDK({
                session: session,
                mode: "development",
                recipe: {
                  form: {
                    provider: { name: "react" },
                  },
                },
              });

              const appContainer = "#onesdk-container";

              // 3. Create form and IDV components
              const welcome = oneSdk.component("form", {
                name: "WELCOME",
                type: "ocr",
              });

              const consent = oneSdk.component("form", { name: "CONSENT" });

              const idv = oneSdk.flow("idv");

              const idvLoading = oneSdk.component("form", {
                name: "LOADING",
                title: { label: "Loading..." },
                descriptions: [{ label: "" }],
              });

              const processingLoading = oneSdk.component("form", {
                name: "LOADING",
                title: { label: "Processing..." },
                descriptions: [
                  {
                    label: "Please do not refresh this page or click the back button.",
                  },
                ],
              });

              const submitLoading = oneSdk.component("form", {
                name: "LOADING",
                title: { label: "Submitting verification..." },
                descriptions: [
                  {
                    label: "Please do not refresh this page or click the back button.",
                  },
                ],
              });

              // 4. Wire up welcome → consent → IDV
              welcome.on("form:welcome:ready", () => {
                consent.mount(appContainer);
              });

              consent.on("form:consent:ready", () => {
                idvLoading.mount("#loading-overlay");
                idv.mount(appContainer);
              });

              // 5. Handle loading — IDV init and post-capture processing
              let detectionStarted = false;

              idv.on("loading", (isLoading) => {
                if (!detectionStarted && !isLoading) {
                  idvLoading.unmount();
                }
              });

              idv.on("detection_complete", () => {
                detectionStarted = true;
                processingLoading.mount("#loading-overlay");
              });

              // 6. Handle results
              idv.on("results", async ({ checkStatus }) => {
                processingLoading.unmount();
                if (checkStatus) {
                  submitLoading.mount(appContainer);
                  try {
                    await oneSdk.individual().submit({ verify: true });
                    document.getElementById("onesdk-container").innerHTML =
                      "<h2>Verification complete</h2><p>Your identity has been verified.</p>";
                  } catch (err) {
                    console.error("Submission error:", err);
                  }
                }
              });

              // 7. Handle errors
              idv.on("error", ({ message, payload }) => {
                console.error("IDV error:", message, payload);
                document.getElementById("onesdk-container").innerHTML =
                  "<h2>Verification error</h2><p>Please try again.</p>";
              });

              // 8. Mount welcome screen to start
              welcome.mount(appContainer);
            } catch (error) {
              console.error("OneSDK initialization failed:", error);
            }
          }

          startOneSDK();
        </script>
      </body>
    </html>
    ```
  </Tab>

  <Tab title="React">
    ```jsx theme={null}
    import { useEffect, useRef } from "react";
    import OneSdk from "@frankieone/one-sdk";

    export default function IDVFlow({ session }) {
      const initRef = useRef(false);

      useEffect(() => {
        if (!session || initRef.current) return;
        initRef.current = true;

        (async () => {
          try {
            const oneSdk = await OneSdk({
              session,
              mode: "development",
              recipe: {
                form: {
                  provider: { name: "react" },
                },
              },
            });

            const appContainer = "#onesdk-container";

            const welcome = oneSdk.component("form", { name: "WELCOME", type: "ocr" });
            const consent = oneSdk.component("form", { name: "CONSENT" });
            const idv = oneSdk.flow("idv");

            const idvLoading = oneSdk.component("form", {
              name: "LOADING",
              title: { label: "Loading..." },
              descriptions: [{ label: "" }],
            });

            const processingLoading = oneSdk.component("form", {
              name: "LOADING",
              title: { label: "Processing..." },
              descriptions: [
                {
                  label: "Please do not refresh this page or click the back button.",
                },
              ],
            });

            const submitLoading = oneSdk.component("form", {
              name: "LOADING",
              title: { label: "Submitting verification..." },
              descriptions: [
                {
                  label: "Please do not refresh this page or click the back button.",
                },
              ],
            });

            welcome.on("form:welcome:ready", () => consent.mount(appContainer));
            consent.on("form:consent:ready", () => {
              idvLoading.mount("#loading-overlay");
              idv.mount(appContainer);
            });

            let detectionStarted = false;

            idv.on("loading", (isLoading) => {
              if (!detectionStarted && !isLoading) {
                idvLoading.unmount();
              }
            });

            idv.on("detection_complete", () => {
              detectionStarted = true;
              processingLoading.mount("#loading-overlay");
            });

            idv.on("results", async ({ checkStatus }) => {
              processingLoading.unmount();
              if (checkStatus) {
                submitLoading.mount(appContainer);
                try {
                  await oneSdk.individual().submit({ verify: true });
                  document.getElementById("onesdk-container").innerHTML =
                    "<h2>Verification complete</h2>";
                } catch (err) {
                  console.error("Submission error:", err);
                }
              }
            });

            idv.on("error", ({ message }) => {
              console.error("IDV error:", message);
            });

            welcome.mount(appContainer);
          } catch (error) {
            console.error("OneSDK initialization failed:", error);
          }
        })();
      }, [session]);

      return (
        <div id="onesdk-wrapper" style={{ position: "relative", width: "100%", height: "100vh" }}>
          <div id="onesdk-container" style={{ width: "100%", height: "100%" }} />
          <div
            id="loading-overlay"
            style={{ position: "absolute", top: 0, left: 0, width: "100%", height: "100%", zIndex: 10, background: "#fff" }}
          />
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

## Step-by-Step Breakdown

### 1. Initialize the SDK

Pass the session object to [`OneSDK()`](/docs/sdk-reference/sdk-initialization). Include the `recipe.form.provider` configuration since this flow uses [form components](/docs/sdk-reference/form-module) for the WELCOME and CONSENT screens.

### 2. Add Welcome and Consent Screens

Create WELCOME and CONSENT [form components](/docs/sdk-reference/form-module) to collect user consent before starting the IDV capture. Set `type: "ocr"` on the WELCOME screen. Consent must be collected before verification can proceed — without it, submission will fail.

### 3. Create the IDV Flow

Call [`sdk.flow("idv")`](/docs/sdk-reference/idv-module) to create the identity verification flow. This returns a component that manages the entire camera capture experience.

### 4. Wire Up Events

Listen for [events](/docs/sdk-reference/events):

* `form:welcome:ready` on welcome — user completed the welcome screen, mount consent
* `form:consent:ready` on consent — user gave consent, mount the IDV flow
* `loading` on IDV — show/hide loading screen while IDV component initializes (before capture)
* `detection_complete` on IDV — document capture finished, show processing loading screen
* `results` on IDV — processing complete, `checkStatus` indicates success
* `error` on IDV — an error occurred during capture or processing

<Callout icon="bell" color="#FFCA16" iconType="regular">
  **Unmount clears the container.** Calling `.unmount()` on a component removes **all content** from the element it was mounted to — not just the component itself. Loading screens in this flow are mounted to a **separate overlay element** (`#loading-overlay`) so that unmounting them does not destroy the IDV component underneath. See the [IDV with Review flow](/docs/embedded-flows/idv-review#loading-screens) for a detailed explanation.
</Callout>

### 5. Handle Results

When `results` fires with `checkStatus: true`, mount a loading screen then call [`sdk.individual().submit({ verify: true })`](/docs/sdk-reference/individual-module) to trigger the verification check. The loading screen prevents a blank screen during the async submission.

## Submitting Verification

After the IDV flow returns results, mount a loading screen then submit for verification:

```javascript theme={null}
idv.on("results", async ({ checkStatus }) => {
  processingLoading.unmount();
  if (checkStatus) {
    submitLoading.mount(appContainer);
    try {
      const result = await oneSdk.individual().submit({ verify: true });
      // Handle verification result
    } catch (error) {
      console.error("Verification submission failed:", error);
    }
  }
});
```

See [Individual Module](/docs/sdk-reference/individual-module) for all submission options.

## Provider Configuration

Configure the IDV provider in the SDK recipe:

```javascript theme={null}
const oneSdk = await OneSDK({
  session: session,
  mode: "production",
  recipe: {
    ocr: {
      provideReviewScreen: false,
      provider: { name: "incode" },
    },
    biometrics: {
      provider: { name: "incode" },
    },
  },
});
```

See [Vendor Customizations](/docs/sdk-reference/vendor-customizations) for all provider options.

## Customization Reference

| Aspect                     | Reference                                                          |
| -------------------------- | ------------------------------------------------------------------ |
| SDK initialization options | [SDK Initialization](/docs/sdk-reference/sdk-initialization)       |
| IDV flow configuration     | [IDV Module](/docs/sdk-reference/idv-module)                       |
| Form screen configuration  | [Form Module](/docs/sdk-reference/form-module)                     |
| Individual submission      | [Individual Module](/docs/sdk-reference/individual-module)         |
| Event names and payloads   | [Events](/docs/sdk-reference/events)                               |
| Error handling patterns    | [Error Scenarios](/docs/sdk-reference/error-scenarios)             |
| Provider configuration     | [Vendor Customizations](/docs/sdk-reference/vendor-customizations) |
