Skip to main content

Bio Login with Backend V2

Overview

The Bio Login module verifies a user by capturing a selfie and uploading the captured biometric data to Amani services.

On iOS, BioLogin is created using BioLoginBuilder. The selected capture type determines how the selfie is captured, while the start() and upload() flow remains the same for all capture types.

BioLogin supports the following capture methods:

  • .manualSelfie — the user manually captures the selfie.
  • .autoSelfie — the selfie is captured automatically when the face is positioned correctly.
  • .poseEstimation — the user completes a guided head-pose verification flow before capture.

Each build() call creates a new BioLogin instance. Configuration is not shared between different BioLogin instances.


Requirements

  • AmaniSDK 3.7.4 or higher.
  • Xcode 13+.
  • Swift.
  • Camera permission configured in the application.
  • Microphone permission if required by the selected flow.
  • A valid Amani server URL.
  • A valid BioLogin token.

Basic Flow

The typical BioLogin integration follows these steps:

  1. Create a BioLoginBuilder

    • Set the server URL.
    • Set the BioLogin token.
    • Set the internal BioLogin type using setType(type:).
    • Select the desired selfie capture type.
  2. Configure the selected capture type

    • For .manualSelfie and .autoSelfie, optionally customize selfie messages and colors.
    • For .poseEstimation, optionally customize messages, colors, and guide images.
  3. Build the BioLogin instance

    • Call build().
    • Keep a strong reference to the returned BioLogin instance until the flow is completed.
  4. Start BioLogin

    • Call start().
    • Add the returned UIView to your view hierarchy.
    • The completion callback returns the captured preview image.
  5. Upload the result

    • Call upload() on the same BioLogin instance.
    • Handle the success or failure result.
    • Remove the BioLogin view when the flow is complete.

start() and upload() are common to all BioLogin capture types. Only the Builder configuration changes between Manual Selfie, Auto Selfie, and Pose Estimation.


BioLogin Properties

Keep the BioLogin instance and its view as properties while the flow is active:

private var bioLogin: BioLogin?
private var viewContainer: UIView?

Common Builder Parameters

The following parameters can be used for all BioLogin capture types.

Server URL

Use setUrl(url:) to configure the Amani server URL.

.setUrl(
url: "<YOUR_SERVER_URL>"
)

Token

Use setToken(token:) to configure the BioLogin token.

.setToken(
token: "<YOUR_TOKEN>"
)

Type

Use setType(type:) to configure the internal BioLogin type.

.setType(
type: "XXX_SE_0"
)

Default value:

"XXX_SE_0"

setType(type:) can be configured directly from BioLoginBuilder.

For backwards compatibility, it is also available on the created BioLogin instance:

guard let bioLogin = BioLoginBuilder()
.setUrl(url: "<YOUR_SERVER_URL>")
.setToken(token: "<YOUR_TOKEN>")
.setBioLoginType(type: .autoSelfie)
.build()
else {
return
}

bioLogin.setType(
type: "XXX_SE_0"
)

The recommended usage is to set the type directly on the builder before calling build().

BioLogin Capture Type

Use setBioLoginType(type:) to select the capture mode.

.setBioLoginType(
type: .autoSelfie
)

Available values:

.manualSelfie
.autoSelfie
.poseEstimation

Source

source is optional and defaults to 3.

.setSource(
source: 3
)

Comparison Adapter

comparison_adapter is optional and defaults to 2.

The existing public API name is preserved for backwards compatibility:

.setComparisonAdaptere(
comparison_adapter: 2
)

Manual Selfie Capture

Use .manualSelfie when the user should manually trigger the selfie capture.

Create the BioLogin instance as shown below:

guard let bioLogin = BioLoginBuilder()
.setUrl(
url: "<YOUR_SERVER_URL>"
)
.setToken(
token: "<YOUR_TOKEN>"
)
.setType(
type: "XXX_SE_0"
)
.setBioLoginType(
type: .manualSelfie
)
.build()
else {
print("BioLogin could not be created.")
return
}

self.bioLogin = bioLogin

Manual Selfie uses the same message and color configuration APIs as Auto Selfie.

Manual Selfie Messages

Use setSelfieMessages(key:value:) to override individual selfie messages.

guard let bioLogin = BioLoginBuilder()
.setUrl(
url: "<YOUR_SERVER_URL>"
)
.setToken(
token: "<YOUR_TOKEN>"
)
.setType(
type: "XXX_SE_0"
)
.setBioLoginType(
type: .manualSelfie
)
.setSelfieMessages(
key: .lookStraight,
value: "Look straight at the camera."
)
.setSelfieMessages(
key: .faceTooSmall,
value: "Move closer to the camera."
)
.setSelfieMessages(
key: .faceTooBig,
value: "Move away from the camera."
)
.build()
else {
return
}

Manual Selfie Colors

Use setSelfieColor(key:value:) to override individual colors.

.setSelfieColor(
key: .appBackgroundColor,
value: "000000"
)
.setSelfieColor(
key: .appFontColor,
value: "FFFFFF"
)
.setSelfieColor(
key: .primaryButtonBackgroundColor,
value: "FFFFFF"
)
.setSelfieColor(
key: .ovalBorderColor,
value: "FFFFFF"
)
.setSelfieColor(
key: .ovalBorderSuccessColor,
value: "00FF00"
)

Available selfie message keys:

.faceIsOk
.notInArea
.faceTooSmall
.faceTooBig
.completed
.captureDescription
.lookStraight
.holdPhoneVertically

Available selfie color keys:

.appBackgroundColor
.appFontColor
.primaryButtonBackgroundColor
.ovalBorderSuccessColor
.ovalBorderColor

Auto Selfie Capture

Use .autoSelfie when the selfie should be captured automatically after the face is positioned correctly.

guard let bioLogin = BioLoginBuilder()
.setUrl(
url: "<YOUR_SERVER_URL>"
)
.setToken(
token: "<YOUR_TOKEN>"
)
.setType(
type: "XXX_SE_0"
)
.setBioLoginType(
type: .autoSelfie
)
.build()
else {
print("BioLogin could not be created.")
return
}

self.bioLogin = bioLogin

Auto Selfie Messages

Use setSelfieMessages(key:value:) to customize Auto Selfie messages.

.setSelfieMessages(
key: .faceIsOk,
value: "Please stay still."
)
.setSelfieMessages(
key: .notInArea,
value: "Align your face inside the circle."
)
.setSelfieMessages(
key: .faceTooSmall,
value: "Move closer to the camera."
)
.setSelfieMessages(
key: .faceTooBig,
value: "Move away from the camera."
)
.setSelfieMessages(
key: .lookStraight,
value: "Look straight."
)
.setSelfieMessages(
key: .holdPhoneVertically,
value: "Hold the phone vertically."
)

Auto Selfie Colors

Use setSelfieColor(key:value:) to customize the Auto Selfie UI.

.setSelfieColor(
key: .appBackgroundColor,
value: "000000"
)
.setSelfieColor(
key: .appFontColor,
value: "FFFFFF"
)
.setSelfieColor(
key: .primaryButtonBackgroundColor,
value: "FFFFFF"
)
.setSelfieColor(
key: .ovalBorderColor,
value: "FFFFFF"
)
.setSelfieColor(
key: .ovalBorderSuccessColor,
value: "00FF00"
)

The following APIs are shared by .manualSelfie and .autoSelfie:

setSelfieMessages(key:value:)
setSelfieColor(key:value:)

Colors are provided as hexadecimal strings without the # prefix.


Pose Estimation Capture

Use .poseEstimation when the user should complete a guided head-pose verification flow before capture.

guard let bioLogin = BioLoginBuilder()
.setUrl(
url: "<YOUR_SERVER_URL>"
)
.setToken(
token: "<YOUR_TOKEN>"
)
.setType(
type: "XXX_SE_0"
)
.setBioLoginType(
type: .poseEstimation
)
.build()
else {
print("BioLogin could not be created.")
return
}

self.bioLogin = bioLogin

Pose Estimation supports additional customization for:

  • Messages
  • Colors and screen configuration
  • Main guide images
  • Secondary guide images

Pose Estimation Messages

Use setPoseEstimationMessages(infoMessages:) to override one or more Pose Estimation messages.

.setPoseEstimationMessages(
infoMessages: [
.faceIsOk: "Please stay still.",
.notInArea: "Align your face inside the circle.",
.faceTooSmall: "Move closer to the camera.",
.faceTooBig: "Move away from the camera.",
.turnRight: "Turn your head right.",
.turnLeft: "Turn your head left.",
.turnUp: "Look up.",
.turnDown: "Look down.",
.lookStraight: "Look straight.",
.completed: "Verification completed."
]
)

Available Pose Estimation message keys include:

.faceIsOk
.notInArea
.faceTooSmall
.faceTooBig
.completed
.turnRight
.turnLeft
.turnUp
.turnDown
.lookStraight
.errorMessage
.tryAgain
.errorTitle
.confirm
.next
.holdPhoneVertically
.informationScreenDesc1
.informationScreenDesc2
.informationScreenTitle
.wrongPose
.descriptionHeader
.closedEyes

Pose Estimation Colors and Screen Configuration

Use setPoseEstimationColors(screenConfig:) to customize Pose Estimation appearance and screen configuration.

.setPoseEstimationColors(
screenConfig: [
.appBackgroundColor: "000000",
.appFontColor: "FFFFFF",
.primaryButtonBackgroundColor: "004CFF",
.primaryButtonTextColor: "FFFFFF",
.ovalBorderColor: "FFFFFF",
.ovalBorderSuccessColor: "00FF00",
.poseCount: "2",
.secondaryGuideVisibility: "true",
.buttonRadius: "10"
]
)

Available Pose Estimation configuration keys include:

.appBackgroundColor
.appFontColor
.primaryButtonBackgroundColor
.primaryButtonTextColor
.ovalBorderSuccessColor
.ovalBorderColor
.poseCount
.secondaryGuideVisibility
.buttonRadius

Pose Estimation Main Guide Images

Use setPoseEstimationMainGuideImages(guideImages:) to replace the default main direction images.

.setPoseEstimationMainGuideImages(
guideImages: [
.mainGuideUp: UIImage(named: "pose_up")!,
.mainGuideDown: UIImage(named: "pose_down")!,
.mainGuideLeft: UIImage(named: "pose_left")!,
.mainGuideRight: UIImage(named: "pose_right")!,
.mainGuideStraight: UIImage(named: "pose_straight")!
]
)

Available main guide image keys:

.mainGuideUp
.mainGuideDown
.mainGuideLeft
.mainGuideRight
.mainGuideStraight

Pose Estimation Secondary Guide Images

Use setPoseEstimationSecondaryImages(guideImages:) to replace the secondary direction guide images.

.setPoseEstimationSecondaryImages(
guideImages: [
.secondaryGuideUp: UIImage(named: "arrow_up")!,
.secondaryGuideDown: UIImage(named: "arrow_down")!,
.secondaryGuideLeft: UIImage(named: "arrow_left")!,
.secondaryGuideRight: UIImage(named: "arrow_right")!
]
)

Available secondary guide image keys:

.secondaryGuideUp
.secondaryGuideDown
.secondaryGuideLeft
.secondaryGuideRight

Complete Pose Estimation Builder Example

guard let bioLogin = BioLoginBuilder()
.setUrl(
url: "<YOUR_SERVER_URL>"
)
.setToken(
token: "<YOUR_TOKEN>"
)
.setType(
type: "XXX_SE_0"
)
.setBioLoginType(
type: .poseEstimation
)
.setPoseEstimationColors(
screenConfig: [
.appBackgroundColor: "000000",
.appFontColor: "FFFFFF",
.primaryButtonBackgroundColor: "004CFF",
.primaryButtonTextColor: "FFFFFF",
.ovalBorderColor: "FFFFFF",
.ovalBorderSuccessColor: "00FF00",
.poseCount: "2",
.secondaryGuideVisibility: "true",
.buttonRadius: "10"
]
)
.setPoseEstimationMessages(
infoMessages: [
.faceIsOk: "Please stay still.",
.notInArea: "Align your face inside the circle.",
.faceTooSmall: "Move closer to the camera.",
.faceTooBig: "Move away from the camera.",
.turnRight: "Turn your head right.",
.turnLeft: "Turn your head left.",
.turnUp: "Look up.",
.turnDown: "Look down.",
.lookStraight: "Look straight.",
.completed: "Verification completed."
]
)
.build()
else {
print("BioLogin could not be created.")
return
}

self.bioLogin = bioLogin

Start

After creating a BioLogin instance with any of the capture types above, call start().

start() returns a UIView that must be added to your view hierarchy.

do {

guard let bioLogin = bioLogin else {
return
}

guard let bioLoginView = try bioLogin.start(
completion: { [weak self, weak bioLogin] previewImage in

guard
let self = self,
let bioLogin = bioLogin
else {
return
}

print("BioLogin capture completed")

bioLogin.upload(
location: nil
) { [weak self] result in

guard let self = self else {
return
}

DispatchQueue.main.async {

if result == true {
print("BioLogin upload successful")
} else {
print("BioLogin upload failed")
}

self.viewContainer?.removeFromSuperview()
self.viewContainer = nil
self.bioLogin = nil
}
}
}
) else {
print("BioLogin.start returned nil view")
return
}

self.viewContainer = bioLoginView

DispatchQueue.main.async { [weak self] in

guard let self = self else {
return
}

bioLoginView.frame = self.view.bounds

self.view.addSubview(bioLoginView)
self.view.bringSubviewToFront(bioLoginView)
}

} catch {

print("BioLogin start error: \(error)")
self.bioLogin = nil
}

The same start() flow is used for:

.manualSelfie
.autoSelfie
.poseEstimation

Upload

After the selfie capture is completed, call upload() on the same BioLogin instance.

bioLogin.upload(
location: nil
) { result in

if result == true {
print("BioLogin upload successful")
} else {
print("BioLogin upload failed")
}
}

An optional CLLocation can also be provided:

bioLogin.upload(
location: currentLocation
) { result in

if result == true {
print("BioLogin upload successful")
}
}

The same BioLogin instance that performed the capture must be used for upload().


Complete Pose Estimation Integration Example

final class BioLoginViewController: UIViewController {

private var bioLogin: BioLogin?
private var viewContainer: UIView?

func startBioLogin() {

guard let bioLogin = BioLoginBuilder()
.setUrl(
url: "<YOUR_SERVER_URL>"
)
.setToken(
token: "<YOUR_TOKEN>"
)
.setType(
type: "XXX_SE_0"
)
.setBioLoginType(
type: .poseEstimation
)
.build()
else {
print("BioLogin could not be created.")
return
}

self.bioLogin = bioLogin

do {

guard let bioLoginView = try bioLogin.start(
completion: { [weak self, weak bioLogin] previewImage in

guard
let self = self,
let bioLogin = bioLogin
else {
return
}

print("BioLogin capture completed")

bioLogin.upload(
location: nil
) { [weak self] result in

guard let self = self else {
return
}

DispatchQueue.main.async {

if result == true {
print("BioLogin upload successful")
} else {
print("BioLogin upload failed")
}

self.viewContainer?.removeFromSuperview()
self.viewContainer = nil
self.bioLogin = nil
}
}
}
) else {
print("BioLogin.start returned nil view")
return
}

self.viewContainer = bioLoginView

DispatchQueue.main.async { [weak self] in

guard let self = self else {
return
}

bioLoginView.frame = self.view.bounds

self.view.addSubview(bioLoginView)
self.view.bringSubviewToFront(bioLoginView)
}

} catch {

print("BioLogin start error: \(error)")
self.bioLogin = nil
}
}
}

Builder API Reference

Common Configuration

setUrl(url:)
setToken(token:)
setType(type:)
setBioLoginType(type:)
setSource(source:)
setComparisonAdaptere(comparison_adapter:)

Manual / Auto Selfie Configuration

setSelfieMessages(key:value:)
setSelfieColor(key:value:)

Pose Estimation Configuration

setPoseEstimationMessages(infoMessages:)
setPoseEstimationColors(screenConfig:)
setPoseEstimationMainGuideImages(guideImages:)
setPoseEstimationSecondaryImages(guideImages:)

Build

build()

Returns:

BioLogin?

Notes

  • Create BioLogin using BioLoginBuilder.
  • Each build() call creates an independent BioLogin instance.
  • BioLogin.sharedInstance is not used by the Builder.
  • Set the server with setUrl(url:).
  • Set the token with setToken(token:).
  • Set the internal type with setType(type:).
  • setType(type:) is also available directly on BioLogin for backwards compatibility.
  • Select the capture mode with setBioLoginType(type:).
  • Keep a strong reference to the created BioLogin instance until capture and upload are completed.
  • Use the same BioLogin instance for both start() and upload().
  • .manualSelfie and .autoSelfie use setSelfieMessages and setSelfieColor.
  • .poseEstimation uses the dedicated Pose Estimation configuration APIs.
  • Builder customization values override BioLogin defaults.
  • You do not need to provide every message, color, or guide image.
  • Colors are provided as hexadecimal strings without the # prefix.
  • Call build() after Builder configuration is complete.
  • Call start() only after a successful build().