# Configure Flows Locally and Run End to End

Use this path when the React Native app owns the module order. You define the onboarding flow locally in code with a `flowConfig` array, optionally register listeners to receive per-step results, and run the whole session in one call to `startOnboarding()`. The SDK presents the Incode UI for each module in turn.

Use this pattern when you want full control over the flow in client code. If you prefer to define the flow on the Incode Dashboard instead, see [Run Flows Configured Online](react-native-run-flows-configured-online.md). For other patterns, start from [Common Implementation Patterns](index.md).

> **Before you start**
>
> Make sure the SDK is installed and initialized. See [Getting Started](../react-native-getting-started/index.md) for setup and initialization. Your API URL and API key are provided to you by Incode.

The common path is three objects and one call: build a `sessionConfig`, build a `flowConfig`, and call `startOnboarding()`. Optionally, register step listeners before the call to receive per-module results as they complete.

### Configure Onboarding session

`sessionConfig` is optional for `startOnboarding()`. If you don't need to bind a Dashboard flow, resume a session, or set custom fields, you can omit it.

```ts
const sessionConfig = {
  externalId: 'external-id',
  validationModules: ['id', 'liveness', 'faceRecognition'],
};
```

Useful `sessionConfig` fields include:

| Field                               | Use                                                                                                                                |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `queue`                             | Assign the session to a queue.                                                                                                     |
| `interviewId` / `token`             | Start from a backend-created session.                                                                                              |
| `configurationId`                   | Apply a dashboard flow configuration.                                                                                              |
| `externalId` / `externalCustomerId` | Link the Incode session to your own user/customer ID.                                                                              |
| `validationModules`                 | Select server-side validation modules.                                                                                             |
| `customFields`                      | Attach custom string data.                                                                                                         |
| `e2eEncryptionEnabled`              | Enable E2EE for the session. See [End-to-End Encryption](../react-native-getting-started/react-native-e2ee.md) for the full setup. |
| `mergeSessionRecordings`            | Merge ID and Face recordings.                                                                                                      |
| `voiceConsentLanguage`              | Set `VideoSelfie` voice consent language: `en`, `es`, `pt`, or `he`.                                                               |

Available validation modules:

- `id`
- `liveness`
- `faceRecognition`
- `governmentValidation`
- `governmentFaceValidation`
- `governmentOcrValidation`
- `videoSelfie`

Default validation modules are `id`, `liveness`, and `faceRecognition`.

### Configure Onboarding Flow

```ts
const flowConfig = [
  { module: 'IdScan' },
  { module: 'SelfieScan' },
  { module: 'FaceMatch' },
];
```

Each module is an object with a `module` field and any module-specific configuration as sibling fields:

```ts
const flowConfig = [
  { module: 'IdScan', showTutorial: true, idType: 'id' },
  { module: 'SelfieScan', lensesCheck: false },
  { module: 'FaceMatch', matchType: 'idSelfie' },
];
```

If a module is omitted from the array, it is not shown in the flow. Modules run in the order they appear in the array.

Place dependent modules after the modules they need:

- `FaceMatch` should follow `IdScan` and `SelfieScan`.
- `ProcessId` should follow `IdScanFront` and `IdScanBack`.
- `VideoSelfie` should follow `IdScan` (in `faceMatch` mode) or `SelfieScan` (in `selfieMatch` mode).
- `Aes` should follow `Phone`, `IdScan`, and `SelfieScan`.
- `UserScore` and `Approve` should be at the end.

A few cross-cutting notes:

- Several modules show tutorials by default. Disable them per module by passing `showTutorial: false` (or the module-specific equivalent).
- To display results to the user at the end of the flow, include `{ module: 'UserScore' }`. Use `{ module: 'UserScore', mode: 'fast' }` to use on-device results instead of server-side results.
- To approve the user directly from the client at the end of the flow, include `{ module: 'Approve' }`. Use `{ module: 'Approve', forceApproval: true }` to force approval.

> For the full list of modules you can add and their configuration parameters, see [Modules](../react-native-modules.md).

### Start the onboarding

Call `startOnboarding()` with the `sessionConfig` and `flowConfig`. The call resolves with a result object when the flow finishes. The result only indicates the flow's final outcome (success or user cancellation). It does not contain per-module data. To receive per-module results, register listeners (see below).

```ts
const result = await IncodeSdk.startOnboarding({
  sessionConfig,
  flowConfig,
});

if (result.status === 'userCancelled') {
  console.log('User cancelled onboarding');
}
```

Errors are thrown rather than returned. Wrap the call in a try/catch to handle failures. `startOnboarding()` can throw the following error codes:

- `permissionsDenied`: the user denied a required permission.
- `faceAuthenticationFailed`: a face authentication step failed.
- `sslPinningFailed`: SSL pinning validation failed.
- `locationUnavailable`: required location data could not be obtained.
- `unknown`: an unrecognized native error occurred.

```ts
try {
  await IncodeSdk.startOnboarding({ sessionConfig, flowConfig });
} catch (error) {
  if (error.code === 'permissionsDenied') {
    console.log('User denied some mandatory permission during the flow');
  }
}
```

To listen for the results of the steps in the flow as soon as they're completed, register optional listeners before starting the flow. Each listener returns an unsubscribe function:

```ts
const unsubscribers = [
  IncodeSdk.onSessionCreated((session) => {
    console.log(session.interviewId);
  }),
  IncodeSdk.onStepCompleted({
    module: 'IdScanFront',
    listener: (event) => console.log(event.result),
  }),
  IncodeSdk.onStepCompleted({
    module: 'IdScanBack',
    listener: (event) => console.log(event.result),
  }),
  IncodeSdk.onStepCompleted({
    module: 'ProcessId',
    listener: (event) => console.log(event.result.extendedOcrData),
  }),
  IncodeSdk.onStepCompleted({
    module: 'SelfieScan',
    listener: (event) => console.log(event.result),
  }),
  IncodeSdk.onStepCompleted({
    module: 'FaceMatch',
    listener: (event) => console.log(event.result),
  }),
];
```

Listeners are optional: if you only need the final outcome of the flow, you can rely on the value returned by `startOnboarding()` and skip listener registration. For the shape and fields of each result object passed to listeners, see [Results](../react-native-results.md).

Call each unsubscriber when the screen unmounts.

```ts
React.useEffect(() => {
  const unsubscribers = setupListeners();

  return () => {
    unsubscribers.forEach((unsubscriber) => unsubscriber());
  };
}, []);
```

### Enable session recording

To record ID and Selfie captures, add `recordSessionConfig` to the `startOnboarding()` call:

```ts
await IncodeSdk.startOnboarding({
  sessionConfig,
  flowConfig,
  recordSessionConfig: {
    recordSession: true,
    forcePermissions: false,
  },
});
```

On Android, session recording requires the `-vc` SDK package variant and the video-streaming dependency:

```gradle
implementation 'com.incode.sdk:video-streaming:1.5.5'
```

On iOS, no additional variant or dependency is required. Session recording is included in the main iOS SDK.

## Related pages

- [Common Implementation Patterns](index.md): overview of all integration patterns.
- [Configure Flows Locally and Run Step by Step](react-native-configure-flows-locally-and-run-step-by-step.md): split the same locally configured flow into sections.
- [Run Flows Configured Online](react-native-run-flows-configured-online.md): define the flow on the Dashboard instead of in code.
- [Modules](../react-native-modules.md): the module catalog and per-module configuration parameters.
- [Results](../react-native-results.md): result and error object reference.
- [API Reference](../react-native-api-reference.md): full API specification.

<br />
