Fortface SDK integration in your iOS app
How does it work?
The purpose of our SDK is to capture the photo and send it to our Fortface API. To do this, there is a UIViewController that acts independently of your app, started by an Engine the moment it is established and, after processing, closes automatically.
Our SDK does not communicate directly with the Fortface API, see below for the communication flow:

Below are the instructions for integrating our SDK, the process flow for correctly accessing our service and step-by-step instructions on how to build an Engine.
Installation
Requirement
iOS: minimum supported version is 13.0
Installation
Versions starting from 1.8
1. Import folder via local SPM
Download the file by clicking the link below and unzip it: Fortface.xcframework-1.9.zip
- In your project, go to
Package Dependenciesand click the+at the end of the Packages list. - A new screen to add packages will open. In the bottom-right corner, click
+. - At the bottom of the screen, click
Add localand select the folder you downloaded earlier. - Select your project target and click
Add Package. - The new dependency should appear on the right side of your Xcode under Package Dependencies.
Versions prior to 1.8
1. Add the file to your project
First you need to add the Fortface.framework to your project, download it by clicking on the following link and unzip the file: Fortface.xcframework-1.9.zip.
To include the Fortface SDK dependency in your app, simply add the sdk.framework folder to your project.
Example:
your_project/Fortface.framework

Permission
In order to capture the photo, our SDK needs access to the device's camera. For this reason, permission is requested on first access.
Here are the steps:
- In Xcode, in the project browser tab (on the left), click on the project icon (blue) to select it;
- In the main project tab, in the “TARGETS” section, select your application;
- Info” tab, ‘Custom iOS Target Properties’ section, in the last Key click on the plus sign (+) to add a new property;
- Select “Privacy - Camera Usage Description”;
- In the “Value” field, enter a message explaining why the app needs access to the camera. For example: “You need to authorize access to the camera to capture photos and videos.”
Example:
Pre-initialization
Before starting the capture process, it is necessary to establish the integrity of the device to ensure secure communication with the Fortface API. You therefore need to:
- import our SDK into your app;
- Instantiate
FortfaceSDK.
Establish device integrity
Start the SDK and get the deviceRequestInfo.
- Swift
import Fortface
let deviceRequestInfo = FortfaceSDK.start(isDebugMode: true)
print(deviceRequestInfo)
// ztdTVLuGyQegvUnEtwAzcHbK8RoA9CXTuNRpCi9YXcwlzWpzOff+iOvUMkdprLk1E3npSKmk868x4pdJELztvRwu0auBrQdVFTu4wUI8ne35blqq1fds0ZHkOx8pfZGD4SIIPEVTEg2+uXQ8k6lxg7xoSnGzIPQJBZJmQWyDECXKDlXt+AAzMGN4lIWB2uM3ncwQLHPGDcGx52EgXBt3yQV7xZrCdinlwlDb21GK1kjygkRixqCvcB3LudlD8bYKKZq1PO5+faL0gFp6cTWpU9Fqkf7l9kbMc/5n+RGE83QzcQuLBzphDmIX2EUsqIdKFk/eg8WqAA9iC9YX4271/gt6RXqy2oQVJ4cyqD6bpLcRZtk/kLcW1lbo1h4bWyTyjC3XXnRPZVComA51s3Ouzxm4IxKX/EaTMd88n/ABiuE2s2DDKKKYc+WbqrDJo1btFHuXDA+O66mjrNKP+VE/CgtOrWF6W4x2cnpTNBJALmX23tion0caYxzbYpC18i3U
In FortfaceSDK, start method will be used which has 1 parameter and returns 1 string:
- Parameter
isDebugMode: boolean that enables/disables debug mode. Default valuefalse; - Use
trueto enable debug mode; - Use
falsein production, so that the integrity of the device is checked and, if it is not suitable for transactions, an exception of typeFortfaceExceptionwill be thrown with the message There is something wrong!. - Return stored in
deviceRequestInfo: string used to validate the integrity of the device connected to our SDK. A new one is generated each time the method is called (in the code above is an example).
With deviceRequestInfo in hand, you can now make a handshake call between your back-end and API Fortface.
handshakeis an important security measure for establishing reliable communication between your back-end and API Fortface, making it possible to verify device authenticity, share sensitive information (encryption keys and sessions) and establish a secure channel for data exchange.
A successful handshake ensures that the device is intact and your app has the information it needs to proceed.
Capture
Knowing that the integrity of the device has been established, let's understand how to start the session and use the IFortfaceEngine interface to perform the capture.
Establishing the device session
Implement a class that extends IFortfaceEngine.
- Swift
class Engine: IFortfaceEngine {
init(sessionId: String, sessionKey: String) {
FortfaceManagerSession.start(
engine: self,
sessionId: sessionId,
sessionKey: sessionKey,
orientationManager: FortfaceOrientationManager()
)
}
func finishedSessionEngine(sessionEngineResult: SessionEngineResult) {
switch sessionEngineResult {
case .capture:
captured(data: sessionEngineResult.data ?? Data())
case .cancel:
canceled()
case .timeout:
timeout()
case .deniedCamera:
cameraNotAuthorized()
case .error:
handleErrorAction(sessionDetails: sessionEngineResult.sessionDetails ?? Data())
default: return
}
}
private func captured(data: Data) {
let sdkData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: String]
// Here the flow ends and this is the data to send to the Fortface API
}
private func canceled() {
// Here the user has canceled the capture. You should continue with your cancellation flow
}
private func timeout() {
// Here the capture was canceled because it ran out of time. You must follow the timeout flow
}
private func cameraNotAuthorized() {
// Here the camera permission was not granted by the user. You must follow the camera permission flow
}
private func handleErrorAction(sessionDetails: Data) {
// Here we receive a JSON with the type of error that occurred.
}
}
In this class, initialize FortfaceManagerSession and its start method which has 3 parameters:
sessionId: session id, generated in the Fortface API;sessionKey: encryption key generated in API Fortface;orientationManager: the class responsible for knowing the orientation of the device;getGeolocation: Define whether the SDK should collect location coordinates for anti-fraud reinforcement. (optional)
- Swift
class FortfaceOrientationManager: IFortfaceOrientationManager {
private func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
Mock data for example:
sessionId = “nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2k”
sessionKey = “-----BEGIN PUBLIC KEY----- \nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2k+o81Oiti4TDezZYD8Q\nzj2RjO5f/YQHGmC1v7CWC4AJpD9+FOXBBO1pImaSg1gb8kOobRFGWbVdiHm35+PF\nTJceH31r+jKnvfc1TshsQVGtYLm7x5E/GFcjpGx9LdSxiXC6cHdCJf3o02/lytBa\nu8NCoH9FpPjyKrdGdSRb2haviAuEV4N1UBd5uZIsacVqZj52i1z+I94gLVKBZ/UV\npaxjLPWWngmaxbyKE0sEbt9JGleiCb2P1kZA9sU4L4Po7WBNk0+QOsvW9QjvS1+6\ntcZwwIDll2LyUceiFgxF6GkuFcHlBZDDtzymDDC2IYrf9/FNBOPeV1JHXON8T6DY\nAwIDAQAB\n- ----END PUBLIC KEY-----\n”
The string that represents the sessionKey contains special characters (such as the line break \n) that must be preserved exactly as received from the Fortface API. Be careful with any accidental manipulation that may occur in:
- Form inputs
- Logs and monitoring systems
- String processing in your backend
- Transfers between services
- Database storage
Any change to these characters may cause the key validation to fail. Make sure the key is passed to the SDK exactly as received from the Fortface API.
For local frontend development only, you may reuse the same valid sessionKey as a mock as many times as necessary. The single-use restriction applies only in the context of backend development, when the Fortface API validates the key.
Understanding the code snippet:
initwill make the call toFortfaceManagerSession.start;- The session is created and the camera is rendered on the screen to capture the face of the user;
- The data is encrypted and sent along with the captured photo to API Fortface;
- The return occurs in the
finishedSessionEnginefunction, which is a callback; sessionEngineResultis the object that has 3 properties:data,actionandsessionDetails.- If
sessionEngineResult.actionreturns the valuecaptureit is because the flow went as expected and returned the capture data; datacontains encrypted data and can be converted into JSON to make it easier to manipulate. The 4 keys are generated by the SDK, sent to your back-end and then to the Fortface API.
{
key: String,
data: String,
imgData: String,
imgPreview: String
}
-
If
sessionEngineResult.actionreturns the valuecancel, it's because the user canceled the capture by tapping the Back button, so follow the cancellation flow; -
It is possible to hide the Back button and, consequently, not have
action cancel, more details in the Customization topic. -
If
sessionEngineResult.actionhas a value oftimeout, it means that the time set for capture has elapsed, so you should follow the timeout flow. -
This
actionrepresents the amount of time that the SDK is open, whether it is capturing or not. When it runs out, the SDK is closed and the camera is closed; -
The default time is 30 seconds:
-
If you want to keep it, you don't need to do anything;
-
If you want to change it, just customize the value in seconds, more details in the Customization topic.
-
If
sessionEngineResult.actionhas a value ofdeniedCamera, it means that the user did not allow access to the camera when the permission alert appeared. You should therefore follow the camera permission flow. -
If
sessionEngineResult.actionhas a value oferror, it means that an error occurred during document capture or upload. You should follow the error flow.- The type of error is returned in the
sessionDetailsJSON which can be decoded using theSessionDetailsModel. Currently, the errors received can be:- documentNotFound: code returned when the selected file (PDF/Image) cannot be found.
- fileSizeTooBig: code returned when the selected file (PDF/Image) is larger than the allowed limit of 4MB.
- fileCorrupted: code returned when the selected file (PDF/Image) is corrupted.
- The type of error is returned in the
Versioning
To find out which version of our SDK is being used, simply call the function FortfaceSDK.getVersion() which will return a String with its value. Example:
let sdkVersion = FortfaceSDK.getVersion()
print(sdkVersion)
// 1.5.2
Full screen mode
By default, our SDK is displayed in full screen mode in portrait orientation. This setting is valid for all supported devices. However, on tablets, it is possible to set the orientation to horizontal (landscape) or automatic, allowing the SDK to follow the orientation of the device in use.
On iOS, it is necessary to add this setting to the AppDelegate of the integrator application so that the orientationManager can adapt in cases of screen rotation.
- Swift
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
(...)
var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
}
If the SDK is configured for an orientation other than portrait and run on a smartphone, it will automatically be displayed in portrait, ignoring the customization made. The possible configuration values are:
- Kotlin
customizer.screenMode.mode = .modal
customizer.cameraBackground.color = .red // modal da tela de câmera
customizer.instructionsBackground.color = .white // modal da tela de instruções
Modal mode
We offer the option of customizing the display of the SDK's capture stream in a modal that overlays the client application's screen. This functionality is only available for tablets. When configured and run on smartphones, the SDK will adopt full-screen display behavior in portrait orientation. In modal mode, you can customize the background color.
- Kotlin
customizer.screenMode.mode = .modal
customizer.cameraBackground.color = .red // camera screen modal
customizer.instructionsBackground.color = .white // instructions screen modal
Cancel callback and timeout
When an attempt to capture the user's face is not completed successfully, for example when the user cancels the capture or when the capture doesn't take place during the specified time, it is important that the event is sent to the backend so that we have the correct metrics for the success or failure of the captures.
To allow us to have the data of the canceled or timeout capture, our SDK has callbacks in the cancel capture action and in the capture timeout action.
The SessionEngineResult received in the finishedSessionEngine function is an object in the Data() format which has 2 properties: date and action (action performed in the SDK). Previously, the date field was only filled in at the end of the face capture.
As seen above in Capture, the data contains encrypted data and can be converted into JSON. However, unlike the capture, in this scenario after conversion to JSON, we will only have the following fields:
{
key: String,
data: String
}
Reminder: The key and data keys are generated by the SDK, sent to your back-end and then to the Fortface API.
Implementation example
-
we have identified in the SDK that there has been a capture cancellation.
-
We create the encrypted object.
-
Finish the SDK and send the generated payload and the action taken.
-
In the implementation app, within the class that extends the
IFortfaceEngine, it is detected that an action has taken place.
- Swift
class Engine: IFortfaceEngine {
...
func finishedSessionEngine(sessionEngineResult: SessionEngineResult) {
switch sessionEngineResult {
case .capture:
captured(data: sessionEngineResult.data ?? Data())
// when the cancel action is detected, the canceled function is called
// which receives the date generated in the SDK.
case .cancel:
canceled(data: sessionEngineResult.data ?? Data())
case .timeout:
timeout(data: sessionEngineResult.data ?? Data())
default: return
}
}
private func canceled(data: Data) {
// send the cancellation payload to a metrics API
metricService(data: Data)
}
private func metricService(data: Data) {
// we take the object of type Data and serialize it in JSON
if let metricRequest = try? JSONSerialization.jsonObject(with: self.actionServiceData, options: [])
as? [String: String] {
// transforms into an object of type Metric
let request = getMetricRequest(sdkJsonDataRequest: metricRequest)
// calls the Service layer, sending the Metric to the API
serviceAPI.postSessionMetric(metricRequest: request){ response, error in }
}
}
private func getMetricRequest(sdkJsonDataRequest: [String: String]) -> Metric {
let sdkData = SdkData(
key: sdkJsonDataRequest["key"], data: sdkJsonDataRequest["data"], imgData: nil)
return Metric(sdkData: sdkData)
}
...
}
- Metric object sent to the API
- Swift
import Foundation
struct Metric: Codable {
let sdkData: SdkData?
}
- SdkData object
- Swift
import Foundation
struct SdkData: Codable {
let key: String?
let data: String?
let imgData: String?
}
Summary
- Check minimum requirements, add folder and authorize access to camera;
- Capture
deviceRequestInfo; - Do
handshake; - Start Engine;
- Receive data in callback;
- Send to API Fortface;
- Receive response from API Fortface and proceed with your business rule.