Skip to main content
Version: iOS SDK Latest (6.0.0)

Liveness check

Introduction

The liveness checks allow you to check whether the person whose document you're scanning, actually is the one using the app at the moment. This module should be used after doing a scan with either the Core or NFC module. By using the Liveness check component, you can set up a few simple tasks that the user can perform to confirm that they are alive. We also built in 4 default checks that allow you to simply start the liveness check.

Available checks:

  • Close eyes check: User is asked to close their eyes for two seconds.
  • Head tilt check (left, right or both): User needs to tilt head 15 degrees.
  • Speech check: User is asked to pronounce the names of 3 types of fruits.
  • Face match check: User is asked to take a selfie, the face is matched to the one provided when creating the check. This can be either the document image, or the face image from the NFC module result.

Liveness example flow

In the Result processing section, you will find extensive information about the way the results of this check are processed.

Starting a liveness check

The most basic way to start the liveness checks is to just call VerifaiLiveness.start(over:).

Starting Verifai Liveness using the Result block
do {
try VerifaiLiveness.start(over: self) { result in
switch result {
case .failure(_):
print("Error or cancellation")
case .success(let livenessResult):
// Continue with result
let checksPassed = livenessResult.automaticChecksPassed
// etc....
}
}
} catch {
print("🚫 Unhandled error: \(error)")
}
Starting Verifai Liveness using the concurrency
do {
// Start the liveness check
let livenessResult = try await VerifaiLiveness.start(over: self)
// Continue with result
let checksPassed = livenessResult.automaticChecksPassed
// etc....
} catch {
print("🚫 Error or cancelled: \(error)")
}

This only offers a small amount of functionality, so in order to take full advantage of the provided checks, you'll have to supply VerifaiLiveness with more parameters. The full signature can be viewed on the right side.

Full signature
public static func start(over viewController: UIViewController,
livenessChecks: [VerifaiLivenessCheck]?,
resultBlock: @escaping VerifaiResultBlock<VerifaiLivenessCheckResults>) throws -> UINavigationController

You can also set the Liveness check to use a more custom set of checks that you can setup yourself. On the example below we run the Liveness check only with a face match check and a head tilt check. You can also use custom initializers that we provided to use the default instruction. These initializers can be found further below at the Requirements part of this document.

Example of using some custom checks
static func performLivenessCheck(documentImage: UIImage, presenter: UIViewController) {
// Setup where the checks will be saved (like in the documents folder)
guard let documentsPathURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
print("Unable to find documents folder")
return
}
// Setup the checks
let faceMatchingCheck = VerifaiFaceMatchingLivenessCheck(documentImage: documentImage,
instruction: "Your custom instruction message for the check or nil if you want to use the default one")
guard let headTiltCheck = VerifaiTiltLivenessCheck(faceAngle: 20.0,
instruction: "Your custom instruction message for the check or
nil if you want to use the default one") else {
print("Invalid check setup, we validate some tests before accepting them")
return
}

// Define requirements
let checkRequirements = [
faceMatchingCheck,
headTiltCheck
]
do {
try VerifaiLiveness.start(over: presenter,
livenessChecks: checkRequirements,
resultBlock: { checkResult in
switch checkResult {
case .failure:
print("Error or cancellation")
case .success(let livenessResult):
// Continue with result
let checksPassed = livenessResult.automaticChecksPassed
dump(checksPassed) // If all checks passed
// You'll see 2 result objects after the next dump,
// in the recordingUrl for one you'll find an mp4 for one check and a jpg for the other
dump(livenessResult.resultList)
}
})
} catch {
print("🚫 Unhandled error: \(error)")
}
}

Set a configuration for the Liveness module

You can configure the following settings by defining a VerifaiLivenessCheckConfiguration item, and set it in VerifaiLiveness.configure.

SettingDescriptionDefault
resultPathThe path of the directory in which the result videos / images will be stored. If nil then no images/videos will be stored.nil
showDismissButtonShows a cancel button in the left bar button item of the navigationBartrue
customDismissButtonTitleThe title of the dismiss button, if empty the title will be "Cancel"nil
showSkipButtonShows a skip button on each liveness check, allowing the user to skip a liveness check.true
customSkipButtonTitleThe title of the skip button, if empty the title will be "Skip".nil

Result Video / images location

If desired the recordings can be saved to a location on the device. Set the resultPath URL in the VerifaiLivenessCheckConfiguration object to indicate where the recordings will be saved. The exact URL for each result gets returned in the result object. If you leave this empty then the checks will still be performed but nothing will be recorded. In that case all the result url's in the result object will be nil.

Checks

The liveness check consists of a series of checks that the user has to proceed through. A default list of five checks is already provided by us and shuffled randomly before the SDK is presented. If you do not define your own liveness checks then the default list will be used.

If you want to have control over which checks are displayed and in what order you can supply your own list of requirements. The following requirements are available:

RequirementHow to create
SpeechVerifaiSpeechLivenessCheck(speechRequirement:locale:)
Left tiltVerifaiTiltLivenessCheck.leftTiltLivenessCheck(faceAngle:)
Right tiltVerifaiTiltLivenessCheck.rightTiltLivenessCheck(faceAngle:)
Close eyesVerifaiCloseEyesLivenessCheck(duration:)
Face MatchVerifaiFaceMatchingLivenessCheck(documentImage:)

These are the only requirements allowed. Subclassing VerifaiLivenessCheck is not supported and will result in a failure with error VerifaiLCError.undefinedLivenessCheck.

All these requirements provide a default localized instruction for the user, but you can also supply your own custom instruction string. An example of this can be seen on the right at the start of this segment.

Example:

In this example we make some requirements
let closeEyesCheck = VerifaiCloseEyesLivenessCheck(duration: 2)
let tiltLeft = VerifaiTiltLivenessCheck.leftTiltLivenessCheck()
let tiltRight = VerifaiTiltLivenessCheck.rightTiltLivenessCheck()
let speech = VerifaiSpeechLivenessCheck(speechRequirement: "apple banana pizza",
locale: Locale(identifier: "en-US"))
let faceMatch = VerifaiFaceMatchingLivenessCheck(documentImage: documentImage)
let requirements: [VerifaiLivenessCheck?] = [faceMatch,
tiltLeft,
speech,
closeEyesCheck,
tiltRight]
// Shuffle and filter out nil requirements
let filteredRequirements = requirements.shuffled().compactMap { $0 }

Face matching

To check whether the a user is the person on the document, a selfie can be compared with the document image securely on our backend. It is also possible to use the face image from the NFC chip for this. And return if the face is a match. It will also return the confidence percentage of the match.

To use the face matching simply add a VerifaiFaceMatchingLivenessCheck to the requirements. You can only add one face matching check to the array. If more than one face matching requirement is added then an error will be thrown.

Result Processing

Once the checks are completed, Verifai will return a VerifaiLivenessCheckResults object, which contains a list of all the VerifaiLivenessCheckResult (no s) objects. However, the checks now include 3 extra variables with the results:

Liveness check module result

VerifaiLivenessCheckResult

FieldTypeDescription
automaticChecksPassedBoolIf all checks have success or undetermined status
successRatioFloatnumber of checks divided by number of success status results
resultList[VerifaiLivenessCheckResult]list of VerifaiLivenessCheckResult objects for further processing

Liveness check result list items

VerifaiLivenessCheckResult

Every check produces such a result. It is composed of the original check with additional result fields.

FieldTypeDescription
checkVerifaiLivenessCheckReference to the actual check provided at the start
resultPathURL?The location of the result recording or image
statusStatusThe status of the check

Status

We also supply the status of a check in the result. A check's status can be one of the following:

ValueDescription
successCheck was completed successfully
undeterminedCheck hasn't been performed yet or could not be performed
skippedCheck was skipped
failedCheck failed to be performed because of an error

Video / Image location

In order to see the actual results of the Liveness checks you have to supply a location where Verifai can save media of recordings or photos of the checks. This location resultPath: URL? is nil by default, indicating no recordings will be saved at all. Links to the final recordings are provided in VerifaiLivenessCheckResult.resultPath: URL?.

Face matching result

This check has a special VerifaiLivenessCheckResults object with the added match and confidence result info:

ValueDescriptionType
matchWhether the face matches the face provided in the check, if nil then no check was done or failed.Bool?
confidenceThe confidence score that the faces match [0-1], if nil then no check was done or failed.Double?
checkThe check this result is linked to.VerifaiLivenessCheck
resultUrlThe location of the video or image linked to the check (if available).URL?
statusThe status of the check.Status

Liveness module errors

What follows is an overview of the errors Verifai can return with a description of what causes them. All errors are of the VerifaiLCError type.

ErrorDescriptionPossible solutions
undefinedLivenessCheckUndefined liveness check submitted.Ensure you're using one of the provided liveness check types as subclassing is not allowed
lowSpaceForOperationLow space detected on the device to save the liveness check data.Ask your user to free up space on the device and retry
internalAVErrorAn internal AV error occurred.An internal error occurred during recording, please try again
cancelledLivenessChecksThe user cancelled the liveness check operation.Show an error condition or ask the user to retry
internetConnectionFailedThere was no internet available to perform the face matching check.Ensure there's an active internet connection and retry
internalErrorThere was an internal error processing the request, please contact us.Show an error condition or ask the user to retry. If the issue persists then contact us.
tooManyFaceMatchChecksMultiple face match checks found, only one face match check per session is allowed.Ensure you only provide one face match check in the requirements array