# Face Match

The Face Match module compares the user's selfie against their ID photo, their NFC chip photo, or both in a 3-way match. It then returns a confidence score. Matching is performed on the server. The module can also report whether the face already belongs to an existing user.

For an overview of this module and how it works, see [Face Match](https://developer.incode.com/docs/face-match).

How you use this module depends on your [integration pattern](https://developer.incode.com/docs/android-common-implementation-patterns#integration-patterns). In Patterns 1 and 2, you add the module to a `FlowConfig` in code as shown on this page. In Pattern 3, you define your modules and configuration in Dashboard as a Flow or Workflow and reference it by ID with `startFlow()` or `startWorkflow()` as shown on [Run Flows Configured in Dashboard](https://developer.incode.com/docs/android-run-flows-configured-online).

Face Match is not available in [Capture-Only mode](https://developer.incode.com/docs/android-capture-only-sdk); adding it there throws `ModuleNotAvailableException`.

## Add Face Match

1. Add an [ID Scan](https://developer.incode.com/docs/android-id-scan) or [QR Scan](https://developer.incode.com/docs/android-qr-scan) module, and a [Selfie Scan](https://developer.incode.com/docs/android-selfie-scan) module, before Face Match. Face Match depends on these earlier capture steps so there are two faces to compare.
2. Add the module with one of the `addFaceMatch` overloads:

   ```kotlin
   // Default configuration
   flowConfigBuilder.addFaceMatch()

   // Custom configuration
   flowConfigBuilder.addFaceMatch(faceMatch)
   ```
   ```java
   // Default configuration
   flowConfigBuilder.addFaceMatch();

   // Custom configuration
   flowConfigBuilder.addFaceMatch(faceMatch);
   ```

Face Match ships both a v1 (legacy View) and a v2 (Jetpack Compose) UI; the active one depends on your Incode configuration. Contact your Incode representative to enable v2.

### Example

The example below adds ID Scan and Selfie Scan before Face Match, builds a `FaceMatch` module comparing the ID photo against the selfie, and listens for the result through `onFaceMatchCompleted()`.

```kotlin
val faceMatch = FaceMatch.Builder()
    .setMatchType(FaceMatch.MatchType.ID_SELFIE)
    .build()

val flowConfig = FlowConfig.Builder()
    .addID()
    .addSelfieScan()
    .addFaceMatch(faceMatch)
    .build()

val onboardingListener = object : IncodeWelcome.OnboardingListener() {
    override fun onFaceMatchCompleted(faceMatchResult: FaceMatchResult) {
        // Face match completed
    }

    override fun onError(error: Throwable) {
        // Onboarding flow was aborted due to error
    }
}

IncodeWelcome.getInstance().startOnboarding(
    activityContext,
    sessionConfig,
    flowConfig,
    onboardingListener
)
```
```java
FaceMatch faceMatch = new FaceMatch.Builder()
    .setMatchType(FaceMatch.MatchType.ID_SELFIE)
    .build();

FlowConfig flowConfig = new FlowConfig.Builder()
    .addID()
    .addSelfieScan()
    .addFaceMatch(faceMatch)
    .build();

IncodeWelcome.OnboardingListener onboardingListener = new IncodeWelcome.OnboardingListener() {
    @Override
    public void onFaceMatchCompleted(@NonNull FaceMatchResult faceMatchResult) {
        // Face match completed
    }

    @Override
    public void onError(@NonNull Throwable error) {
        // Onboarding flow was aborted due to error
    }
};

IncodeWelcome.getInstance().startOnboarding(
    activityContext,
    sessionConfig,
    flowConfig,
    onboardingListener
);
```

## Configuration Options

Configure the module with `FaceMatch.Builder`. The table below lists the most commonly used options.

| Setting                        | Description                                                                                                                                           |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `setMatchType`                 | Selects what to compare: `MatchType.ID_SELFIE`, `MatchType.NFC_SELFIE`, or `MatchType.NFC_3_WAY`. The NFC match types require captured NFC chip data. |
| `setIdCategory`                | Sets the `IdCategory` values to match against, replacing any previously set values.                                                                   |
| `setShowUserExists`            | Shows or hides the label indicating the user already exists. Default is `false`.                                                                      |
| `setShowLivenessResult`        | Shows or hides the liveness result label. Default is `false`.                                                                                         |
| `setFaceMatchAnimationEnabled` | Shows or hides the face match animation. Disabling it puts the module in compact UI mode.                                                             |

The match type and the thresholds used to decide a pass or fail also depend on your Incode Flow or Workflow configuration, not just these options.

For the complete option set, see `FaceMatch.Builder` in [API Reference](https://developer.incode.com/docs/android-api-reference).

## Result

Face Match delivers a `FaceMatchResult` to the `onFaceMatchCompleted(faceMatchResult)` callback on `OnboardingListener`. Key fields include:

- `confidence`: Recognition confidence between the selfie and ID photo. A value above `0.6` means the selfie matched the front ID; `-1` means no front ID was uploaded.
- `secondIdConfidence`: Recognition confidence between the selfie and the second ID photo (same scale as `confidence`).
- `nfcVsSelfieConfidence`: Recognition confidence between the selfie and NFC chip photo. A value above `0.6` means a match; `-1` means no NFC image was uploaded.
- `nfcVsIdConfidence`: Recognition confidence between the front ID photo and NFC chip photo. A value above `0.6` means a match; `-1` means either no front ID image or no NFC image was uploaded.
- `idCategories`: The list of `IdCategory` values used in the face matching process.
- `isExistingUser`: `true` if the user already exists in the database; otherwise, `false`.
- `existingInterviewId`: The interview ID of the existing user, if one exists; otherwise, `null`.
- `isNameMatched`: `true` if the existing user's name matches the current user's name (use together with `isExistingUser`); otherwise, `false`.
- `isFaceMatched`: If the faces matched.
- Fields inherited from `BaseResult`:
  - `resultCode`: The `ResultCode` for this result.
  - `error`: When `resultCode` is `ERROR`, the `Throwable` that caused it; otherwise, `null`.
  - `deviceStats`: The `DeviceStats` snapshot of the device state when the result was produced.
  - `motionStatus`: Device motion assessment during capture. One of the following:
    - `UNCLEAR`: Motion could not be determined; the default.
    - `PASS`: Device motion was within acceptable limits.
    - `FAIL`: Excessive device motion was detected.

If the module fails, the onboarding flow is aborted and the error surfaces through `OnboardingListener.onError(Throwable)`. Face Match does not deliver a module-specific exception subtype.

For all fields, see `FaceMatchResult` in [API Reference](https://developer.incode.com/docs/android-api-reference).
