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

# Split Flow (OCR + Biometrics)

> Wire together separate OCR and Biometrics components with form screens for maximum control over the document capture and facial verification journey.

## Overview

The split flow uses the OCR and Biometrics components separately instead of the combined IDV flow. This gives you full control over the journey between document capture and facial verification — you can customize loading states, handle OCR results before proceeding to biometrics, and optionally insert a review screen between the two.

**Modules used:** [`ocr`](/docs/sdk-reference/ocr-module), [`biometrics`](/docs/sdk-reference/biometrics-module), [`form`](/docs/sdk-reference/form-module) (WELCOME, CONSENT, DOCUMENT, 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>

<Callout icon="bell" color="#FFCA16" iconType="regular">
  **Daon provider:** Document selection and the `documents` parameter are not required when using the Daon provider — Daon provides its own document type selection screen. To use custom document selection instead of Daon's built-in screen, contact your FrankieOne account team.
</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="Document Selection">
    User selects the type of document to capture.
  </Step>

  <Step title="OCR Capture">
    Camera-based document capture and data extraction.
  </Step>

  <Step title="Biometrics Capture">
    Facial verification via selfie capture.
  </Step>

  <Step title="Result">
    Verification outcome displayed.
  </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 Split 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: "split-" + Date.now(),
                    },
                  }),
                }
              );
              const session = await tokenResponse.json();

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

              const appContainer = "#onesdk-container";

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

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

              const documentForm = oneSdk.component("form", {
                name: "DOCUMENT",
                showPreps: true,
              });

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

              const biometrics = oneSdk.component("biometrics");

              // 4. Wire up form navigation
              welcome.mount(appContainer);

              welcome.on("form:welcome:ready", () => {
                consent.mount(appContainer);
              });

              consent.on("form:consent:ready", () => {
                documentForm.mount(appContainer);
              });

              // 5. Handle document selection → OCR capture
              documentForm.on("form:document:ready", ({ inputInfo }) => {
                loading.mount("#loading-overlay");
                const docType = inputInfo.documentType;

                const ocr = oneSdk.component("ocr", {
                  documents: [{ type: docType, countries: ["AUS"] }],
                });

                ocr.mount(appContainer);

                ocr.on("loading", (isLoading) => {
                  if (!isLoading) {
                    loading.unmount();
                  }
                });

                ocr.on("error", (err) => {
                  console.error("OCR error:", err);
                });

                // 6. Handle OCR results → Biometrics
                ocr.on("results", ({ document }) => {
                  if (document) {
                    loading.mount("#loading-overlay");
                    biometrics.mount(appContainer);
                  }
                });
              });

              // 7. Handle biometrics
              let biometricsError = false;

              biometrics.on("detection_failed", () => {
                biometricsError = true;
              });

              biometrics.on("session_closed", () => {
                if (biometricsError) {
                  biometrics.mount(appContainer);
                  biometricsError = false;
                }
              });

              biometrics.on("loading", (isLoading) => {
                if (!isLoading) {
                  loading.unmount();
                }
              });

              biometrics.on("results", (result) => {
                document.getElementById("onesdk-container").innerHTML =
                  "<h2>Verification complete</h2>";
              });

              biometrics.on("error", (err) => {
                console.error("Biometrics error:", err);
              });
            } 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 SplitFlow({ session }) {
      const initRef = useRef(false);

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

        (async () => {
          try {
            const oneSdk = await OneSdk({
              session,
              mode: "development",
              recipe: {
                ocr: { maxDocumentCount: 3 },
                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 documentForm = oneSdk.component("form", { name: "DOCUMENT", showPreps: true });

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

            const biometrics = oneSdk.component("biometrics");

            welcome.mount(appContainer);

            welcome.on("form:welcome:ready", () => consent.mount(appContainer));
            consent.on("form:consent:ready", () => documentForm.mount(appContainer));

            documentForm.on("form:document:ready", ({ inputInfo }) => {
              loading.mount("#loading-overlay");
              const ocr = oneSdk.component("ocr", {
                documents: [{ type: inputInfo.documentType, countries: ["AUS"] }],
              });

              ocr.mount(appContainer);

              ocr.on("loading", (isLoading) => {
                if (!isLoading) loading.unmount();
              });

              ocr.on("error", (err) => console.error("OCR error:", err));

              ocr.on("results", ({ document }) => {
                if (document) {
                  loading.mount("#loading-overlay");
                  biometrics.mount(appContainer);
                }
              });
            });

            let biometricsError = false;
            biometrics.on("detection_failed", () => { biometricsError = true; });
            biometrics.on("session_closed", () => {
              if (biometricsError) {
                biometrics.mount(appContainer);
                biometricsError = false;
              }
            });

            biometrics.on("loading", (isLoading) => {
              if (!isLoading) loading.unmount();
            });

            biometrics.on("results", () => {
              document.getElementById("onesdk-container").innerHTML =
                "<h2>Verification complete</h2>";
            });

            biometrics.on("error", (err) => console.error("Biometrics error:", err));
          } 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 `ocr` and `form.provider` recipe configuration.

### 2. Configure Components

Create [form components](/docs/sdk-reference/form-module) for Welcome, Consent, Document selection, and a shared Loading screen. Create the [`ocr`](/docs/sdk-reference/ocr-module) and [`biometrics`](/docs/sdk-reference/biometrics-module) components separately.

### 3. Wire Up Events

Use [`.on(event)`](/docs/sdk-reference/events) listeners to navigate between screens and transition from OCR to biometrics. A single loading screen is reused for both OCR and biometrics initialization — mounted to the overlay before each component, and unmounted when the component is ready.

<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 OCR or biometrics component underneath. See the [IDV with Review flow](/docs/embedded-flows/idv-review#loading-screens) for a detailed explanation.
</Callout>

### 4. Handle Results

Listen for `results` on both the OCR and biometrics components. See [Error Scenarios](/docs/sdk-reference/error-scenarios) for details on handling failures.

## OCR Results Handling

When the OCR component completes, it returns the extracted document data and the flow proceeds to biometrics:

```javascript theme={null}
ocr.on("results", ({ document }) => {
  if (document) {
    // Access extracted fields if needed
    const dob = document.ocrResult.dateOfBirth;
    const name = document.ocrResult.fullName;

    // Proceed to biometrics
    loading.mount("#loading-overlay");
    biometrics.mount(appContainer);
  }
});
```

See [OCR Module](/docs/sdk-reference/ocr-module) for all available result fields.

## Biometrics Error Recovery

The biometrics component may fail due to camera issues or detection problems. Implement automatic retry:

```javascript theme={null}
let biometricsError = false;

biometrics.on("detection_failed", () => {
  biometricsError = true;
});

biometrics.on("session_closed", () => {
  if (biometricsError) {
    biometrics.mount(appContainer);
    biometricsError = false;
  }
});
```

See [Biometrics Module](/docs/sdk-reference/biometrics-module) for all events and configuration options.

## Adding a Review Screen

To let users confirm extracted data before proceeding to biometrics, insert a review screen between OCR and biometrics:

```javascript theme={null}
const review = oneSdk.component("form", {
  name: "REVIEW",
  type: "ocr",
});

ocr.on("results", ({ document }) => {
  if (document) {
    review.mount(appContainer);
  }
});

review.on("form:review:ready", () => {
  loading.mount("#loading-overlay");
  biometrics.mount(appContainer);
});
```

## Customization Reference

| Aspect                      | Reference                                                    |
| --------------------------- | ------------------------------------------------------------ |
| SDK initialization options  | [SDK Initialization](/docs/sdk-reference/sdk-initialization) |
| OCR component configuration | [OCR Module](/docs/sdk-reference/ocr-module)                 |
| Biometrics configuration    | [Biometrics Module](/docs/sdk-reference/biometrics-module)   |
| Form screen configuration   | [Form Module](/docs/sdk-reference/form-module)               |
| Screen names and types      | [Form Screens](/docs/sdk-reference/form-module/screens)      |
| Event names and payloads    | [Events](/docs/sdk-reference/events)                         |
| Error handling patterns     | [Error Scenarios](/docs/sdk-reference/error-scenarios)       |
