> ## Documentation Index
> Fetch the complete documentation index at: https://eurusys-6c0957fa.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Biometrics (fingerprint)

> How fingerprint capture and matching work, and how the recommendation handler lets the user pick the best finger.

Biometric verification adds a fingerprint match to an Emirates ID validation. You attach a **`fingerprint`** sub-object to an `emiratesIdCard` or `emiratesIdManual` request; the SDK then captures a print and submits it alongside the EID for the backend to match against the resident's enrolled fingers.

<Info>
  Biometrics is available on the **Emirates ID** methods only. `passportManual` has no biometric variant.
</Info>

## The flow

```mermaid theme={null}
sequenceDiagram
    participant App as Your app
    participant SDK
    participant VG as Validation Gateway
    participant FP as Fingerprint sensor
    App->>SDK: validate(EID + fingerprint{ handler })
    SDK->>VG: look up resident's recommended fingers
    VG-->>SDK: quality-ranked finger list (best first)
    SDK->>App: onFingerRecommendation(rankedFingers)
    App-->>SDK: FingerSelection (recommended / custom / cancel)
    SDK->>FP: capture selected finger
    FP-->>SDK: fingerprint image
    SDK->>VG: validate (EID + fingerprint)
    VG-->>SDK: verification result
```

1. You pass a `fingerprint` containing the sensor's `readerId`, a **recommendation handler**, and an optional capture timeout.
2. The SDK asks the backend which fingers the resident has enrolled, ranked by quality (best first). The list may be **empty** if the resident isn't enrolled.
3. The SDK invokes your handler with that list. You return a `FingerSelection`: the recommended finger, a custom finger, or cancel.
4. The SDK captures that finger on the sensor and submits the EID + print together.

## The recommendation handler

The handler is where you put UI — show the ranked list, let the operator pick, or auto-select. It's an async/suspend callback in every SDK.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val handler = FingerRecommendationHandler { recommended ->
        if (recommended.isNotEmpty()) FingerSelection.Recommended(recommended.first())
        else FingerSelection.Custom(Finger.RightIndex)
    }

    mbkyc.validate(
        EmiratesIdCard(
            readerId    = scReader.id,
            fingerprint = Fingerprint(
                readerId              = fpReader.id,
                recommendationHandler = handler,
                captureTimeoutMs      = 10_000,
            ),
        )
    ).getOrThrow()
    ```
  </Tab>

  <Tab title="Swift">
    ```swift theme={null}
    final class MyFingerDelegate: NSObject, FingerRecommendationDelegate {
        func onFingerRecommendation(
            recommendedFingers: [NSNumber],
            completion: @escaping (FingerSelection) -> Void
        ) {
            let finger = recommendedFingers.first
                .flatMap { Finger(rawValue: $0.uint32Value) } ?? .rightIndex
            completion(.recommended(finger))   // or .custom(.leftMiddle) / .cancel()
        }
    }
    ```
  </Tab>

  <Tab title="TypeScript">
    ```ts theme={null}
    fingerprint: {
      readerId: fpReader.id,
      recommendationCallback: {
        async onFingerRecommendation(recommendedFingers /* Finger[] */) {
          return FingerSelection.recommended(recommendedFingers[0]);
          // or FingerSelection.custom(finger) / FingerSelection.cancel()
        },
      },
      captureTimeoutMs: 10_000,
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    Fingerprint fp = new Fingerprint(fpReader.id, recommended ->
        recommended.isEmpty()
            ? FingerSelection.custom(Finger.RightThumb)
            : FingerSelection.recommended(recommended.get(0)));
    ```
  </Tab>
</Tabs>

## FingerSelection

Your handler returns one of:

| Selection             | Meaning                                                                     |
| --------------------- | --------------------------------------------------------------------------- |
| `Recommended(finger)` | Capture the backend-recommended finger you picked from the list.            |
| `Custom(finger)`      | Capture a specific finger you chose yourself (e.g. when the list is empty). |
| `Cancel()`            | Abort the biometric capture.                                                |

<Warning>
  Handle the **empty list** case — it means the resident has no quality-ranked enrolled fingers to recommend. Fall back to a `Custom` finger or surface a clear message to the operator rather than indexing into an empty list.
</Warning>

## Hardware

Fingerprint capture needs a supported sensor and, on desktop, the matching signed service installed (e.g. the Morpho service). See [supported hardware](/overview/introduction#supported-hardware) and the [package matrix](/distribution/package-matrix). On Android, include the relevant `service-fingerprint-*-android` AAR and wire the [USB-attach intent](/sdks/android#usb-device-attach-host-app-responsibility).
