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.
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:)
.
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)")
}
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.
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.
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
.
Setting | Description | Default |
---|---|---|
resultPath | The path of the directory in which the result videos / images will be stored. If nil then no images/videos will be stored. | nil |
showDismissButton | Shows a cancel button in the left bar button item of the navigationBar | true |
customDismissButtonTitle | The title of the dismiss button, if empty the title will be "Cancel" | nil |
showSkipButton | Shows a skip button on each liveness check, allowing the user to skip a liveness check. | true |
customSkipButtonTitle | The 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:
Requirement | How to create |
---|---|
Speech | VerifaiSpeechLivenessCheck(speechRequirement:locale:) |
Left tilt | VerifaiTiltLivenessCheck.leftTiltLivenessCheck(faceAngle:) |
Right tilt | VerifaiTiltLivenessCheck.rightTiltLivenessCheck(faceAngle:) |
Close eyes | VerifaiCloseEyesLivenessCheck(duration:) |
Face Match | VerifaiFaceMatchingLivenessCheck(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:
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
Field | Type | Description |
---|---|---|
automaticChecksPassed | Bool | If all checks have success or undetermined status |
successRatio | Float | number 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.
Field | Type | Description |
---|---|---|
check | VerifaiLivenessCheck | Reference to the actual check provided at the start |
resultPath | URL? | The location of the result recording or image |
status | Status | The 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:
Value | Description |
---|---|
success | Check was completed successfully |
undetermined | Check hasn't been performed yet or could not be performed |
skipped | Check was skipped |
failed | Check 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:
Value | Description | Type |
---|---|---|
match | Whether the face matches the face provided in the check, if nil then no check was done or failed. | Bool? |
confidence | The confidence score that the faces match [0-1], if nil then no check was done or failed. | Double? |
check | The check this result is linked to. | VerifaiLivenessCheck |
resultUrl | The location of the video or image linked to the check (if available). | URL? |
status | The 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.
Error | Description | Possible solutions |
---|---|---|
undefinedLivenessCheck | Undefined liveness check submitted. | Ensure you're using one of the provided liveness check types as subclassing is not allowed |
lowSpaceForOperation | Low space detected on the device to save the liveness check data. | Ask your user to free up space on the device and retry |
internalAVError | An internal AV error occurred. | An internal error occurred during recording, please try again |
cancelledLivenessChecks | The user cancelled the liveness check operation. | Show an error condition or ask the user to retry |
internetConnectionFailed | There was no internet available to perform the face matching check. | Ensure there's an active internet connection and retry |
internalError | There 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. |
tooManyFaceMatchChecks | Multiple 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 |