Verigram
Verigram
  • Docs
  • Changelog
  • Feature requests
  • Support portal
    • Verilive JavaScript SDK
    • Verilive Android SDK
    • Verilive iOS SDK
    • Backend API
Docs / Integrations

Verilive iOS SDK

A guide to Integrating Liveness Verification into your iOS mobile application
Verilive iOS SDK

Verilive iOS SDK is a library that allows you to integrate liveness verification into your iOS application. It provides a simple UIViewController-based API with a delegate pattern for receiving results.

Requirements

  • Deployment Target: iOS 13+

  • Permissions: Camera (NSCameraUsageDescription in Info.plist)

  • Orientation: Portrait only (enforced by SDK)

Integration Steps

  1. Create a session in your backend by making a POST request to /liveness2/session endpoint.

    #!/usr/bin/env bash
    API_URL="<API_URL>"
    API_KEY="<your-api-key>"
    API_SECRET="<your-api-secret>"
    FLOW_ID="<your-flow-id>"
    PERSON_ID="<your-person-id>"
    
    ### THE LINES BELOW DOES NOT REQUIRE ANY MODIFICATIONS ###
    
    API_PATH="/liveness2/session"
    TIMESTAMP=$(date +%s)
    SIGNABLE_STR=$(echo -n -e "$TIMESTAMP$API_PATH")
    HMAC_DIGEST=$(echo -n $SIGNABLE_STR | openssl sha256 -hmac "$API_SECRET" | cut -d' ' -f2)
    DATA_JSON=$(cat <<-EOF
    {
      "person_id": "$PERSON_ID",
      "flow_id": "$FLOW_ID"
    }
    EOF
    )
    
    curl -i -X POST "https://$API_URL$API_PATH" \
    -H "Content-Type: application/json" \
    -H "X-Verigram-Api-Version: 2.0" \
    -H "X-Verigram-Api-Key: $API_KEY" \
    -H "X-Verigram-Hmac-SHA256: $HMAC_DIGEST" \
    -H "X-Verigram-Ts: $TIMESTAMP" \
    -d "$DATA_JSON"
    

    The endpoint returns a JSON object containing session_id, access_token, person_id, and flow_id. Pass these values directly to your iOS app.

  2. Add camera usage description to your app's Info.plist:

    <key>NSCameraUsageDescription</key>
    <string>Camera access is required for liveness verification</string>
    
  3. Create and present Verilive2ViewController:

    import Verilive2
    
    let veriliveVC = Verilive2ViewController()
    veriliveVC.params = VeriliveParams(
        personId: "your-person-id",
        accessToken: "your-access-token",
        flowId: "your-flow-id",
        sessionId: "your-session-id"
    )
    veriliveVC.delegate = self
    veriliveVC.modalPresentationStyle = .fullScreen
    veriliveVC.isModalInPresentation = true
    present(veriliveVC, animated: false)
    
  4. Implement the delegate to receive results:

    extension YourViewController: Verilive2ViewControllerDelegate {
        func verilivePassed(result: VeriliveResult) {
            dismiss(animated: true)
            // Verification succeeded
            // Fetch the final verdict from your backend using flow_id
        }func veriliveFailed(result: VeriliveResult) {
        dismiss(animated: true)
        let errorCode = result.errorCode
        let errorMessage = result.errorMessage
        // Handle failure
    }
    }
    
  5. Handle the result

    If verilivePassed is called, you must fetch the final verdict from your backend using the flow_id. The iOS SDK does not provide the liveness verdict directly. This behavior is deliberate; frontend results are not reliable and can be tampered with by an attacker.

    To get the results of the Flow, make a GET request to the endpoint /flow/{flow_id}/result:

    curl -X GET https://<API_URL>/flow/{flow-id}/result \
      -H 'Content-Type: application/json' \
      -H 'X-Verigram-Api-Version: 2.0' \
      -H 'X-Verigram-Api-Key: <your-api-key>'
    

API Reference

Verilive2ViewController

A UIViewController subclass that hosts the liveness verification flow.

public class Verilive2ViewController: UIViewController {
    public var delegate: Verilive2ViewControllerDelegate?
    public var params: VeriliveParams?
}

Properties:

  • delegate: Verilive2ViewControllerDelegate? — Delegate for receiving verification results. Must be set before presenting.

  • params: VeriliveParams? — Configuration parameters for the verification flow. Must be set before presenting.

  • onRetry: ((_ sessionId: String, _ errorCode: String, _ attemptsLeft: Int) -> VeriliveRetryResult?)? — Optional. Callback for consumer-managed retry. Called on a background thread after the user taps "Retry". Return new session credentials, or nil to fall back to server-managed retry.

Methods:

  • cancel() — Cancel the ongoing verification flow. Dismisses the SDK and invokes veriliveFailed(result:) on the delegate with VeriliveResult(success: false, errorCode: "CANCELLED_BY_USER", ...). Use this when the host application needs to programmatically abort verification (e.g., the user taps a cancel button in the host UI outside the SDK modal).

Presentation:

  • Must be presented modally with .fullScreen presentation style.

  • Set isModalInPresentation = true to prevent interactive dismissal.

  • The SDK enforces portrait orientation internally.

  • Present with animated: false for best UX.

Verilive2ViewControllerDelegate

Protocol for receiving verification results.

public protocol Verilive2ViewControllerDelegate: AnyObject {
    func verilivePassed(result: VeriliveResult)
    func veriliveFailed(result: VeriliveResult)
}

verilivePassed(result:)

Called when liveness verification succeeds. The result.success field is always true; errorCode and errorMessage are nil.

veriliveFailed(result:)

Called when liveness verification fails, the user cancels, or an error occurs. The result.success field is always false; inspect errorCode for programmatic handling and errorMessage for display.

VeriliveParams

Configuration for starting a verification flow.

public struct VeriliveParams {
    public let baseUrl: String?
    public let personId: String
    public let accessToken: String
    public let flowId: String
    public let sessionId: String
    public let attemptsLeft: Int?

    public init(
        baseUrl: String? = nil,
        personId: String,
        accessToken: String,
        flowId: String,
        sessionId: String,
        attemptsLeft: Int? = nil
    )
}

Fields:

  • baseUrl: String? — Optional. API base URL. Use nil for the default endpoint. Set to your on-premises URL if applicable.

  • personId: String — The unique identifier for the individual undergoing verification.

  • accessToken: String — Authentication token obtained from the backend.

  • flowId: String — The flow identifier for the verification session.

  • sessionId: String — A unique ID for the current session/attempt.

  • attemptsLeft: Int? — Optional. Number of retry attempts allowed (default: nil).

VeriliveResult

Strongly-typed result returned to the delegate.

public struct VeriliveResult: Equatable {
    public let success: Bool
    public let errorCode: String?
    public let errorMessage: String?
}

Fields:

  • success: Bool — true if the liveness check passed, false otherwise (failed, cancelled, or errored).

  • errorCode: String? — Machine-readable error code for programmatic handling. See Error Codes below. nil when success == true.

  • errorMessage: String? — Human-readable error description. nil when success == true.

VeriliveRetryResult

Return type for the onRetry callback.

public struct VeriliveRetryResult {
    public let sessionId: String
    public let accessToken: String
    public let attemptsLeft: Int
}

Cancellation

To cancel the verification flow from the host application (for example, in response to a user action outside the SDK modal), call cancel() on the Verilive2ViewController instance:

veriliveVC.cancel()

This dismisses the SDK and invokes the delegate's veriliveFailed(result:) method with:

  • result.success == false

  • result.errorCode == "CANCELLED_BY_USER"

The SDK does not expose an in-UI cancel button — swipe-to-dismiss is blocked via isModalInPresentation = true — so cancel() is the only way to programmatically abort the flow before it reaches a natural success/failure state.


Retry Handling

The SDK supports two retry modes:

SDK-managed retry (default)

When the liveness check fails and attemptsLeft > 0, the SDK automatically shows a retry screen and handles the retry internally via the server endpoint.

let vc = Verilive2ViewController()
vc.params = VeriliveParams(
    personId: personId,
    accessToken: accessToken,
    flowId: flowId,
    sessionId: sessionId,
    attemptsLeft: 3
)

Consumer-managed retry

Set onRetry on the view controller to handle retry logic yourself. The callback is called on a background thread after the user taps "Retry", so you can make synchronous network calls.

let vc = Verilive2ViewController()
vc.params = VeriliveParams(...)
vc.delegate = self
vc.onRetry = { sessionId, errorCode, attemptsLeft in
    // Request new session credentials from your backend (runs on background thread)
    let semaphore = DispatchSemaphore(value: 0)
    var retryResult: VeriliveRetryResult?

    var request = URLRequest(url: URL(string: "https://your-api.com/retry-session")!)
    request.httpMethod = "POST"
    URLSession.shared.dataTask(with: request) { data, _, _ in
        // parse response
        retryResult = VeriliveRetryResult(
            sessionId: newSessionId,
            accessToken: newAccessToken,
            attemptsLeft: attemptsLeft - 1
        )
        semaphore.signal()
    }.resume()

    semaphore.wait()
    return retryResult
}

If the callback returns nil, the SDK falls back to server-managed retry.


Error Handling

Errors are communicated through the veriliveFailed delegate method via the VeriliveResult struct. Use errorCode for programmatic handling and errorMessage for display.

Scenario

errorCode

errorMessage

Liveness check failed

LIVENESS_FAILED

Error description

Server error

SERVER_ERROR

Server error description

Network error

NETWORK_ERROR

Network error description

SDK initialization error

INTERNAL_ERROR

Error description

Host called cancel()

CANCELLED_BY_USER

"User cancelled the flow"

Error Codes

Error Code

Description

LIVENESS_FAILED

The liveness check did not pass. The user's face was not verified as live.

SERVER_ERROR

The backend returned an error response during the verification process.

NETWORK_ERROR

A network connectivity issue prevented the verification from completing.

INTERNAL_ERROR

An unexpected internal error occurred.

CANCELLED_BY_USER

The host application called cancel() on Verilive2ViewController.

Example:

func veriliveFailed(result: VeriliveResult) {
    dismiss(animated: true)

    switch result.errorCode {
    case "LIVENESS_FAILED":
        print("Liveness failed: \(result.errorMessage ?? "")")
    case "NETWORK_ERROR":
        print("Network error: \(result.errorMessage ?? "")")
    case "SERVER_ERROR":
        print("Server error: \(result.errorMessage ?? "")")
    case "CANCELLED_BY_USER":
        print("User cancelled")
    default:
        print("Error: \(result.errorMessage ?? "Unknown")")
    }
}

Permissions

The SDK requires camera access. Add the following to your app's Info.plist:

<key>NSCameraUsageDescription</key>
<string>Camera access is required for liveness verification</string>

The SDK handles camera permission requests internally:

  • If the user has not been asked yet, the SDK requests permission automatically.

  • If the user denied camera access, the SDK shows an alert with a link to Settings.


Usage Example

import UIKit
import Verilive2

class MainViewController: UIViewController, Verilive2ViewControllerDelegate {

    var veriliveVC: Verilive2ViewController?

    func startVerification(
        personId: String,
        accessToken: String,
        flowId: String,
        sessionId: String
    ) {
        let vc = Verilive2ViewController()
        vc.params = VeriliveParams(
            personId: personId,
            accessToken: accessToken,
            flowId: flowId,
            sessionId: sessionId,
            attemptsLeft: 3
        )
        vc.delegate = self
        vc.modalPresentationStyle = .fullScreen
        vc.isModalInPresentation = true
        self.veriliveVC = vc
        present(vc, animated: false)
    }

    // MARK: - Verilive2ViewControllerDelegate

    func verilivePassed(result: VeriliveResult) {
        dismiss(animated: true) {
            // Verification succeeded
            // Fetch the final verdict from your backend using flow_id
        }
    }

    func veriliveFailed(result: VeriliveResult) {
        dismiss(animated: true) {
            let errorCode = result.errorCode ?? "UNKNOWN"
            let errorMessage = result.errorMessage ?? ""
            // Handle failure using errorCode for programmatic logic
        }
    }
}

PrevVerilive Android SDK
NextBackend API
Was this helpful?