# Selfie

The Selfie module captures the user's face with their device's camera and runs configurable liveness, face recognition, and image-quality checks. It can enroll new users so their face can be matched against an ID photo or used for later authentication. It can optionally capture depth and a video-liveness clip via Deepsight, and it backs the [Face Match](https://developer.incode.com/docs/module-face-match) and [Face Authentication](https://developer.incode.com/docs/module-face-authentication) modules.

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

How you use this module depends on your integration pattern. When the app defines the steps in code, you add the module to an `IncdOnboardingFlowConfiguration` as shown below; when the flow is defined in Dashboard, you reference it by session token and let the back end drive the steps. See [Integration Approaches](https://developer.incode.com/docs/ios-flow-configuration). For [1:1](https://developer.incode.com/docs/glossary#11-face-authentication) and [1:N](https://developer.incode.com/docs/glossary#1n-face-authentication) face login of returning users, iOS uses a separate `startFaceLogin` flow rather than a mode on this module; see [Face Authentication](https://developer.incode.com/docs/module-face-authentication).

**Availability:** All variants; the `-l` build adds extra local-liveness options.

## Add Selfie Scan

Add the module with `addSelfieScan()` on your `IncdOnboardingFlowConfiguration`. Call it with no arguments for the default configuration, or pass options to customize it. Most onboarding flows require Selfie, and some modules depend on ordering; for example, [Face Match](https://developer.incode.com/docs/module-face-match) needs Selfie and an ID or NFC capture added first.

```swift
// Default configuration
flowConfig.addSelfieScan()

// Custom configuration
flowConfig.addSelfieScan(
    showTutorials: true,
    lensesCheck: true,
    faceMaskCheck: true,
    closedEyesCheck: true,
    headCoverCheck: true,
    cameraFacing: .front,
    deepsight: DeepsightConfiguration(
        enabled: true,
        modality: .singleFrameWithDepthAndVideo,
        motion: true
    )
)
```

Selfie ships both a v1 and a v2 capture UI; the SDK selects the active one.

### Example

The example below builds a flow with a Selfie module with tutorials shown, starts onboarding, and receives the result through the `onSelfieScanCompleted` delegate callback.

```swift
let flow = IncdOnboardingFlowConfiguration()
flow.addSelfieScan(showTutorials: true)

IncdOnboardingManager.shared.startOnboarding(
    sessionConfig: IncdOnboardingSessionConfiguration(token: "<SESSION_TOKEN>"),
    flowConfig: flow,
    delegate: self
)

// ...

extension MyViewController: IncdOnboardingDelegate {
    func onSelfieScanCompleted(_ result: SelfieScanResult) {
        // Final selfie result
        if let error = result.error {
            // Handle SelfieScanError
        }
    }

    func onSelfieAttemptCompleted(_ result: SelfieScanResult) {
        // Optional: per-attempt result
    }
}
```

## Configuration Options

Pass these parameters to `addSelfieScan()`. Any parameter left `nil` falls back to the SDK/back-end default.

These options aren't the only factor. Your backend Flow or Workflow configuration can also determine where liveness and recognition run, as well as the effective Deepsight behavior for a given step.

| Option                 | Type                     | Description                                                                                                                                                                                    |
| ---------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `showTutorials`        | `Bool?`                  | Shows a tutorial before capture.                                                                                                                                                               |
| `lensesCheck`          | `Bool?`                  | Enables eyeglasses/contact lenses detection during capture.                                                                                                                                    |
| `faceMaskCheck`        | `Bool?`                  | Enables face-mask detection during capture.                                                                                                                                                    |
| `closedEyesCheck`      | `Bool?`                  | Enables closed eyes detection during capture.                                                                                                                                                  |
| `headCoverCheck`       | `Bool?`                  | Enables head covering detection during capture.                                                                                                                                                |
| `cameraFacing`         | `CameraFacing?`          | `.front` or `.back`.                                                                                                                                                                           |
| `streamFrames`         | `Bool?`                  | Enables frame streaming during capture.                                                                                                                                                        |
| `enableAudioStream`    | `Bool?`                  | Enables audio streaming during capture.                                                                                                                                                        |
| `customLogo`           | `UIImage?`               | Displays a custom logo on the capture screen.                                                                                                                                                  |
| `deepsight`            | `DeepsightConfiguration` | `enabled`, `modality` (`.singleFrame`, `.singleFrameWithDepth`, or `.singleFrameWithDepthAndVideo`), and `motion`. Defaults to `.default` (`enabled: false`, `.singleFrame`, `motion: false`). |
| `imageQualitySeverity` | `ImageQualitySeverity`   | `.ultraLow` (default), `.low`, `.medium`, `.high`, or `.ultraHigh`.                                                                                                                            |
| `occlusionCheck`       | `OcclusionCheck`         | `.disabled` (default) or `.enabled(severity)` where severity is `.low` (default), `.medium`, or `.high`.                                                                                       |

The `-l` build adds a `performLocalLiveness` parameter to `addSelfieScan()`.

The older `requireDepthData` and `videoLivenessRecording` parameters are deprecated. Use `deepsight` instead. `videoLivenessRecording: true` maps to `DeepsightModality.singleFrameWithDepthAndVideo`.

For flows where captured media stays on the device, see [Capture-Only Mode](https://developer.incode.com/docs/ios-capture-only-sdk).

## Result

Selfie delivers a `SelfieScanResult` to the delegate:

```swift
func onSelfieScanCompleted(_ result: SelfieScanResult)   // final result
func onSelfieAttemptCompleted(_ result: SelfieScanResult) // per attempt
```

Key fields include:

- `spoofAttempt: Bool?`: `true` if a spoof attempt was detected, `false` if the user appears to be a real person, `nil` when it couldn't be determined because an unexpected error occurred.
- `image: UIImage?`: The captured selfie image.
- `selfieBase64: String?`: The Base64-encoded selfie image.
- `selfieEncryptedBase64: String?`: The encrypted Base64-encoded selfie image.
- `frameWithDepth: String?`: The Base64-encoded frame with depth data (Deepsight).
- `metadata: String?`: Proprietary capture metadata.
- `videoFileURL: URL?`: The local URL of the video-liveness recording.
- `presignedVideoFileURL: URL?`: The URL of the video-liveness file prepared for backend transmission.
- `deviceStats: DeviceStats?`: The device state at capture; `deviceStats.motionStatus` (`MotionStatus`) is the device-motion assessment.
- `idealCaptureEnvironmentTestResult: Int?`: The result of the ideal-capture-environment test.
- `allAttemptsExhausted: Bool`: `true` if no further capture or upload retries are available.
- `faceLoginResult: FaceLoginResult?`: Populated for face-login operations. Sub-fields: `success: Bool?`, `customerUUID: String?`, `interviewId: String?`, `interviewToken: String?`, `token: String?`, `transactionId: String?`, `hasFaceMask: Bool?`, and `hasLenses: Bool?`.
- `error: SelfieScanError?`: Set when the scan did not complete successfully.

## Errors

`SelfieScanError` cases:

- `error(IncdError)`
- `permissionsDenied`
- `spoofDetected`
- `lensesDetected`
- `faceMaskDetected`
- `tooDark`
- `closedEyesDetected`
- `headCoverDetected`
- `faceNotAligned`
- `faceOccluded`
- `userCancelled`
- `userNotFound`
- `noFaceTemplateStored`
- `userBlacklisted`
- `manualFaceNotFound`
- `secondFactorAuthorizationFailed`
- `streamAudioPermissionsDenied`

<br />
