---
icon: device-mobile
label: iOS SDK
---

# iOS SDK

## Overview

The VerifEye iOS SDK (`Verifeye`) is a SwiftUI library for embedding the VerifEye verification flow directly into your iOS application. Its single entry point is the [`VerifyVerifier`](#verifyverifier) view, which renders the full client-side experience — camera access, consent, liveness, and image capture — against a verification session you create server-side.

The SDK handles the on-device capture and the calls to the VerifEye Service. It does **not** create sessions or expose results on its own:

- **Your backend** creates a verification session (using your API key) and returns its `sessionId` and `accessToken` to the app.
- **The `VerifyVerifier` view** runs the verification using those credentials and invokes `onVerificationCompleted` when the flow finishes.
- **Your backend** fetches the outcome from the [VerifEye Service API](/cloud-apis-web-sdks/verifeye-service-api/#get-session-result) once the flow completes.

!!!tip
Session creation requires your API key and must happen **server-side only**. Never ship your API key inside the app — the SDK only ever receives a short-lived session `accessToken`.
!!!

---

## Prerequisites

- **iOS 16** or higher, and **SwiftUI**.
- A **VerifEye account and API key** from the [VerifEye Developer Console](https://verifeye-console.realeyes.ai/).
- A **server-side endpoint** that creates a verification session and returns its `sessionId` and `accessToken` (see [Quick Start](#quick-start)).
- An **`NSCameraUsageDescription`** entry in your app's `Info.plist` — iOS requires it before any camera access. The SDK requests the runtime camera permission itself, but the usage-description string must be provided by the host app.

```xml
<key>NSCameraUsageDescription</key>
<string>We use the camera to verify your identity.</string>
```

---

## Installation

Add the package with Swift Package Manager. In Xcode: **File → Add Package Dependencies…**, or in `Package.swift`:

```swift
dependencies: [
    .package(url: "https://github.com/Realeyes/Verify-Service-iOS", from: "1.0.2")
]
```

Then add `Verifeye` to your target's dependencies and `import Verifeye`.

!!!info Distribution
The SDK ships as a **binary XCFramework** hosted in a public repository and consumed over SPM. Its third-party native dependencies are **embedded inside the framework and hidden from its public interface** — so you `import Verifeye` without adding, resolving, or version-managing any additional packages yourself.
!!!

---

## Quick Start

### 1. Create a session on your server

Call the VerifEye Service to [create a verification session](/cloud-apis-web-sdks/verifeye-service-api/#create-session), authenticating with your API key. The response contains the session ID and a short-lived session token, which you return to the app.

```swift
// Server-side — never expose your API key to the app
// POST https://verifeye-service-api-eu.realeyes.ai/v1/verification/create-session
// Header: Authorization: ApiKey <YOUR_API_KEY>
// Body:
// {
//   "verifierConfigs": {
//     "liveness": { "type": "Verification", "challengeType": "Balanced" },
//     "age": { "type": "CalculationOnly" },
//     "gender": { "type": "CalculationOnly" }
//   }
// }
// Response: { "verificationSessionId": "...", "sessionToken": "..." }
// Return verificationSessionId -> sessionId and sessionToken -> accessToken to the app.
```

### 2. Present the view in your app

Show `VerifyVerifier` once the session credentials are available, and react to completion.

```swift
import SwiftUI
import Verifeye

struct Verification: View {
    let sessionId: String
    let accessToken: String

    var body: some View {
        VerifyVerifier(
            sessionId: sessionId,
            accessToken: accessToken,
            onVerificationCompleted: { completedSessionId in
                // The flow has finished. Fetch the outcome from your backend, which
                // calls the VerifEye Service "Get Session Result" endpoint.
            },
            region: .eu
        )
    }
}
```

!!!tip
`onVerificationCompleted` fires when the flow finishes — it does **not** tell you whether verification passed or failed. Retrieve the result server-side via [Get Session Result](/cloud-apis-web-sdks/verifeye-service-api/#get-session-result) using the `sessionId`.
!!!

### 3. Read the result on your server

When `onVerificationCompleted` fires, have the app notify your backend, then fetch the outcome from the VerifEye Service [Get Session Result](/cloud-apis-web-sdks/verifeye-service-api/#get-session-result) endpoint — again authenticating with your API key, never from the app.

The result stays available for **7 days** after the session was created, and returns **all** captured fields; fields for verifiers you did not enable are `null`. See [Get Session Result](/cloud-apis-web-sdks/verifeye-service-api/#get-session-result) for the full response schema.

---

## API Reference

### `VerifyVerifier`

```swift
public struct VerifyVerifier: View {
    public init(
        sessionId: String,
        accessToken: String,
        onVerificationCompleted: @escaping (String) -> Void,
        region: Region = .eu,
        onServiceError: ((VerifyServiceOperation) -> Void)? = nil,
        consentSkipMode: ConsentSkipMode? = nil,
        headless: Bool = false,
        headlessCallbacks: HeadlessCallbacks? = nil,
        showVerificationSessionId: Bool = false,
        apiBaseUrlOverride: String? = nil
    )
}
```

The main SwiftUI view. Present it to run a single verification session. Each session is single-use — to run another verification, create a new session and present a fresh `VerifyVerifier`.

!!!warning Forcing a new verification
The view holds its verification state in a `@StateObject`, so changing only `sessionId` on an existing view instance does **not** restart the flow. To run another verification, give the view a new identity with `.id(sessionId)` so SwiftUI recreates it:

```swift
VerifyVerifier(
    sessionId: sessionId,
    accessToken: accessToken,
    onVerificationCompleted: { handleCompleted($0) },
    region: .eu
)
.id(sessionId)
```

(The UIKit [`VerifeyePresenter`](#uikit-presenter) already creates a fresh instance on each `present(...)`, so this only applies to the embedded SwiftUI view.)
!!!

#### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `sessionId` | `String` | Yes | The verification session ID returned by your server-side `create-session` call. |
| `accessToken` | `String` | Yes | The short-lived session token returned alongside the session ID. |
| `onVerificationCompleted` | `(String) -> Void` | Yes | Called when the verification flow finishes (regardless of pass/fail). Receives the `sessionId`; use it to fetch the result server-side. |
| `region` | [`Region`](#region) | No | The VerifEye region the session belongs to. Must match the region your backend created the session in. Defaults to `.eu`. |
| `onServiceError` | `((`[`VerifyServiceOperation`](#verifyserviceoperation)`) -> Void)?` | No | Called when a backend operation fails. Receives the operation that was in progress when the error occurred. |
| `consentSkipMode` | [`ConsentSkipMode`](#consentskipmode)`?` | No | Controls whether the camera-consent screen is skipped. When `nil`, the consent screen is always shown. |
| `headless` | `Bool` | No | When `true`, runs the verification without the built-in full-screen UI. See [Headless verification](#headless-verification). Defaults to `false`. |
| `headlessCallbacks` | [`HeadlessCallbacks`](#headlesscallbacks)`?` | No | Lifecycle hooks for headless mode. Ignored unless `headless` is `true`. |
| `showVerificationSessionId` | `Bool` | No | When `true`, displays the verification session ID in the UI (useful for debugging and support). Defaults to `false`. |
| `apiBaseUrlOverride` | `String?` | No | Advanced override for the VerifEye Service base URL the SDK targets. Leave `nil` in production — the SDK then targets the production VerifEye Service for the selected `region`. See [Targeting an environment](#targeting-an-environment). |

---

### Supporting types

#### `Region`

```swift
public enum Region { case eu, us }
```

The supported VerifEye regions.

#### `ConsentSkipMode`

Controls whether the camera-consent screen is shown before capture.

| Member | Value | Meaning |
|--------|-------|---------|
| `ConsentSkipMode.skipIfCameraGranted` | `"1"` | Skip the consent screen only if camera permission has already been granted. |
| `ConsentSkipMode.alwaysSkip` | `"2"` | Always skip the consent screen. |

When the `consentSkipMode` parameter is `nil`, the consent screen is always shown. See [Consent handling](#consent-handling) for details on when it is safe to skip the built-in consent screen.

#### `VerifyServiceOperation`

```swift
public enum VerifyServiceOperation: String {
    case initSession = "init-session"
    case captureImage = "capture-image"
    case verify = "verify"
    case unknown = "unknown"
}
```

Identifies which backend operation was in progress when `onServiceError` was invoked.

#### `HeadlessCallbacks`

Lifecycle hooks used in [headless mode](#headless-verification). All are optional.

```swift
public struct HeadlessCallbacks {
    public var onVerificationStarting: (() -> Void)?
    public var onBeforeCameraAccess: (() -> Void)?
    public var onAfterCameraAccess: (() -> Void)?
}
```

| Callback | Description |
|----------|-------------|
| `onVerificationStarting` | Called just before the verification begins. |
| `onBeforeCameraAccess` | Called immediately before the SDK requests camera access. |
| `onAfterCameraAccess` | Called once camera access has been resolved. |

---

### UIKit presenter

If you integrate from UIKit (rather than embedding the SwiftUI view), present verification as a full-screen flow and receive a typed result via completion.

```swift
import Verifeye

VerifeyePresenter.present(
    from: presentingViewController,
    request: VerifeyeRequest(sessionId: sessionId, accessToken: accessToken, region: .eu),
    completion: { result in
        switch result {
        case .completed(let sessionId): handleCompleted(sessionId)
        case .serviceError(let operation): handleError(operation)
        case .canceled: handleCanceled()
        }
    }
)
```

`VerifeyeRequest` mirrors the view's inputs:

```swift
public struct VerifeyeRequest {
    public init(
        sessionId: String,
        accessToken: String,
        region: Region = .eu,
        consentSkipMode: ConsentSkipMode? = nil,
        headless: Bool = false,
        showVerificationSessionId: Bool = false
    )
}
```

`VerifeyeResult` is an enum:

| Case | Description |
|------|-------------|
| `.completed(sessionId:)` | The flow finished. Fetch the outcome server-side using `sessionId`. |
| `.serviceError(operation:)` | A backend operation failed; `operation` is a [`VerifyServiceOperation`](#verifyserviceoperation). |
| `.canceled` | Reserved. Included so your `switch` stays exhaustive; the SDK does not currently emit this case. |

---

## Consent handling

The `VerifyVerifier` flow accesses the user's camera and processes facial (biometric) data to perform liveness and identity verification. Captured images are used solely to carry out the verification — the SDK does not store them or expose raw biometric data to your application.

### Obtaining consent is your responsibility

The hosting application is responsible for obtaining valid, informed user consent for camera access and biometric processing before a verification runs, and for meeting the requirements of the privacy and biometric-data regulations that apply to your users (e.g. GDPR, BIPA, CCPA). See the [Realeyes Privacy Policy](https://realeyes.ai/privacy-policy/).

### Built-in consent screen

By default, the SDK shows its own consent screen before it requests camera access. This behaviour is controlled by the [`consentSkipMode`](#consentskipmode) parameter:

| `consentSkipMode` | Behaviour |
|-------------------|-----------|
| `nil` (default) | The consent screen is always shown. |
| `skipIfCameraGranted` | The consent screen is skipped only if camera permission has already been granted. |
| `alwaysSkip` | The consent screen is never shown. |

!!!warning
Only disable the built-in consent screen (`skipIfCameraGranted` or `alwaysSkip`) when your application already obtains equivalent, legally valid consent for camera access and biometric processing before showing `VerifyVerifier`. If your application does not handle consent itself, leave the built-in consent screen enabled.
!!!

---

## Usage examples

### Standard verification

The default, interactive flow — the SDK renders its own full-screen UI and drives the user through consent, liveness, and capture.

```swift
VerifyVerifier(
    sessionId: sessionId,
    accessToken: accessToken,
    onVerificationCompleted: { handleCompleted($0) },
    region: .eu
)
```

### Headless verification

Set `headless` to run a verification without the built-in UI — for example, to silently re-verify a user while they keep using your application. Provide `headlessCallbacks` to hook into the lifecycle, and present a fresh `VerifyVerifier` with a new session for each verification cycle.

```swift
VerifyVerifier(
    sessionId: sessionId,
    accessToken: accessToken,
    onVerificationCompleted: { handleCompleted($0) },
    region: .eu,
    onServiceError: { handleError($0) },
    headless: true,
    headlessCallbacks: HeadlessCallbacks(
        onVerificationStarting: { /* ... */ },
        onBeforeCameraAccess: { /* ... */ },
        onAfterCameraAccess: { /* ... */ }
    )
)
```

### Handling service errors

Use `onServiceError` to react to backend failures and inspect which operation failed.

```swift
VerifyVerifier(
    sessionId: sessionId,
    accessToken: accessToken,
    onVerificationCompleted: { handleCompleted($0) },
    region: .eu,
    onServiceError: { operation in
        // operation: .initSession | .captureImage | .verify | .unknown
        print("Verification failed during: \(operation.rawValue)")
    }
)
```

---

## Targeting an environment

In production, leave `apiBaseUrlOverride` unset — the SDK targets the production VerifEye Service for the selected `region` (`https://verifeye-service-eu.realeyes.ai` or `https://verifeye-service-us.realeyes.ai`).

`apiBaseUrlOverride` is an advanced escape hatch for pointing the SDK at a non-production VerifEye environment while integrating; it must not be set for client applications shipping to production.

---

## Next Steps

- [Web SDK](/cloud-apis-web-sdks/web-sdk/) — the equivalent React library for web applications.
- [Android SDK](/mobile-sdks/android-sdk/) — the equivalent library for Android applications.
- [VerifEye Service API](/cloud-apis-web-sdks/verifeye-service-api/) — manage verification configurations and retrieve session results server-side.
- [Authentication](/cloud-apis-web-sdks/authentication/) — API key and bearer token authentication for server-side calls.

---

*Last updated: 2026-08-04*
