Complete Manual for Facial Detection and Filling at iOS Applications
Estimated time: 45-60 minutes for complete configuration
What will you learn from this manual?
That manual will teach you how to implement and use JAAKVisage SDK for automated face detection and video recording in native iOS applications. No advanced technical skills required - Just follow the steps.
Before Start - Checks list
Be sure to have these elements ready:
- Xcode 12.0 + installed
- IOS 12.0 + device (physical, non-simulator)
- Cocoa
- Basic information about Swift / UIKit
- Access to a functional camera
- Facial Test Identification Paper
Contents Index
| Section | What will you do? | Time |
|---|---|---|
| Step 1 | Configure Project and Units | 10 min |
| Step 2 | Basic implementation of SDK | 20 min |
| Step 3 | Configure Camera Permissions | 10 min |
| Step 4 | Record and file management | 15 min |
| Step 5 | Test facial detection | 10 min |
Step 1: Configure Project and Units
Objective
Install JAAKVisage SDK and configure the development environment.
Technical requirements
| Requirement | Version | Mandatory? |
|---|---|---|
| Xcode | 12.0+ | Yes |
| iOS | 12.0+ | Yes |
| Swift | 5.0+ | Yes |
| Cocoa | Last | Yes |
| Physical camera | Required | Yes (non-simulator) |
1.1 Cocoa-Pods installation
# Instalar CocoaPods si no lo tienes
sudo gem install cocoapods
# Create Podfile in your project
cd /ruta/a/tu/proyecto
pod init
1.2 Podfile configuration
platform :ios, '12.0'
target 'YourApp' do
use_frameworks!
# SDK JAAKVisage - Beta Version
pod 'jaak-visage', '>= 1.0.0-beta.1', '< 1.0.0-dev'
end
1.3 Unit installation
# Run installation
pod install
# Important after installation:
# 1. Close Xcode completely if open
# 2. Open .xcworkspace file (NOT .xcodeproj)
open YourApp.xcworkspace
Configure required for compilation
If you find sandboxing errors at compile The project, deactivated User Sandboxing Script:
- Select your target at Xcode
- Go to Build Settings
- Search "Using Sandboxing Script"
- Switch Value To "No"
Step 2: Basic implementation of SDK
Objective
Create JAAKVisage's basic implementation SDK with automatic detection and recording.
2.1 Basic Viewer
import UIKit
import JAAKVisage
import AVKit
class ViewController: UIViewController {
private var detector: JAAKVisageSDK?
private var recordedVideos: [RecordedVideo] = []
// UI Elements
private var statusLabel: UILabel!
private var videosTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupDetector()
}
private func setupUI() {
view.backgroundColor = .systemBackground
title = "Face Detection"
// Status label
statusLabel = UILabel()
statusLabel.text = "Ready to detect face"
statusLabel.textAlignment = .center
statusLabel.numberOfLines = 0
statusLabel.font = .systemFont(ofSize: 16)
statusLabel.translatesAutoresizingMaskIntoConstraints = false
// Reinitiation button
let restartButton = UIButton(type: .system)
restartButton.setTitle("Reiniciar Detector", for: .normal)
restartButton.backgroundColor = .systemBlue
restartButton.setTitleColor(.white, for: .normal)
restartButton.layer.cornerRadius = 8
restartButton.translatesAutoresizingMaskIntoConstraints = false
restartButton.addTarget(self, action: #selector(restartDetector), for: .touchUpInside)
// Table view for videos
videosTableView = UITableView()
videosTableView.delegate = self
videosTableView.dataSource = self
videosTableView.register(UITableViewCell.self, forCellReuseIdentifier: "VideoCell")
videosTableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(statusLabel)
view.addSubview(restartButton)
view.addSubview(videosTableView)
// Layout constraints
NSLayoutConstraint.activate([
statusLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 320),
statusLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
statusLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
restartButton.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: 16),
restartButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
restartButton.heightAnchor.constraint(equalToConstant: 44),
restartButton.widthAnchor.constraint(equalToConstant: 160),
videosTableView.topAnchor.constraint(equalTo: restartButton.bottomAnchor, constant: 16),
videosTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
videosTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
videosTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
private func setupDetector() {
// 1. Basic configuration
var config = JAAKVisageConfiguration()
config.videoDuration = 5.0
config.disableFaceDetection = false
config.enableInstructions = true
// 2. Initiate detector
detector = JAAKVisageSDK(configuration: config)
detector?.delegate = self
// 3. Create preview view
if let previewView = detector?.createPreviewView() {
previewView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(previewView)
NSLayoutConstraint.activate([
previewView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
previewView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
previewView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
previewView.heightAnchor.constraint(equalToConstant: 300)
])
previewView.layer.cornerRadius = 16
previewView.clipsToBounds = true
}
// 4. Initiate detection
do {
try detector?.startDetection()
} catch {
print("Error starting detection:\ (error)")
}
}
// MARK: - Actions
@objc private func restartDetector() {
do {
try detector?.restartDetection()
statusLabel.text = "Reinitiated successfully"
} catch {
statusLabel.text = "Failed to reset:\ (error.locatedDescription)"
}
}
// MARK: - Video Playback
private func playVideo(data: Data, fileName: String) {
let tempDir = FileManager.default.temporaryDirectory
let tempURL = tempDir.appendingPathComponent(fileName)
do {
try data.write(to: tempURL)
let player = AVPlayer(url: tempURL)
let playerController = AVPlayerViewController()
playerController.player = player
present(playerController, animated: true) {
player.play()
}
} catch {
print("Error creating temporary file:\ (error)")
}
}
}
// Structure for video engraving
struct RecordedVideo {
let fileName: String
let data: Data
let recordedAt: Date
let size: Int
var formattedDate: String {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter.string(from: recordedAt)
}
var sizeString: String {
return ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file)
}
}
// MARK: - JAAKVisageSDKDelegate
extension ViewController: JAAKVisageSDKDelegate {
func faceDetector(_ detector: JAAKVisageSDK, didUpdateStatus status: JAAKVisageStatus) {
DispatchQueue.main.async {
self.statusLabel.text = "Estado: \(status.rawValue)"
}
}
func faceDetector(_ detector: JAAKVisageSDK, didCaptureFile result: JAAKFileResult) {
DispatchQueue.main.async {
let video = RecordedVideo(
fileName: result.fileName ?? "video_\(Date().timeIntervalSince1970).mp4",
data: result.data,
recordedAt: Date(),
size: result.fileSize
)
self.recordedVideos.append(video)
self.videosTableView.reloadData()
self.statusLabel.text = "Video capturado: \(video.fileName)"
}
}
func faceDetector(_ detector: JAAKVisageSDK, didEncounterError error: JAAKVisageError) {
DispatchQueue.main.async {
self.statusLabel.text = "Error:\ (error.locatedDescription)"
}
}
func faceDetector(_ detector: JAAKVisageSDK, didDetectFace message: JAAKFaceDetectionMessage) {
if message.faceExists && message.correctPosition {
DispatchQueue.main.async {
self.statusLabel.text = "Retiring face"
}
}
}
}
// MARK: - UITableView DataSource & Delegate
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recordedVideos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "VideoCell", for: indexPath)
let video = recordedVideos[indexPath.row]
cell.textLabel?.text = video.fileName
cell.detailTextLabel?.text = "\(video.formattedDate) • \(video.sizeString)"
cell.accessoryType = .disclosureIndicator
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let video = recordedVideos[indexPath.row]
playVideo(data: video.data, fileName: video.fileName)
}
}
2.2 SwiftIU implementation
import SwiftUI
import JAAKVisage
import AVKit
struct ContentView: View {
@StateObject private var visageManager = VisageManager()
var body: some View {
ScrollView {
VStack(spacing: 16) {
// Detector with Wrapper UIKit
VisageViewWrapper(manager: visageManager)
.frame(height: 400)
.clipShape(RoundedRectangle(cornerRadius: 16))
.padding(.horizontal)
// Status
VStack(spacing: 8) {
Text(visageManager.statusMessage)
.font(.body)
.foregroundColor(.primary)
Text("Estado: \(visageManager.currentStatus.rawValue)")
.font(.caption)
.foregroundColor(.secondary)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Color.blue.opacity(0.1))
.cornerRadius(4)
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(8)
.padding(.horizontal)
// Controles
Button("Reiniciar Detector") {
visageManager.restartDetector()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
// Videos grabados
if !visageManager.recordedVideos.isEmpty {
VStack(alignment: .leading, spacing: 12) {
Text("Videos Grabados (\(visageManager.recordedVideos.count))")
.font(.headline)
.padding(.horizontal)
ForEach(visageManager.recordedVideos.reversed()) { video in
VideoRowView(video: video)
.padding(.horizontal)
}
}
.padding(.bottom)
}
}
}
}
}
// Simplified Manager with video player
class VisageManager: ObservableObject {
@Published var statusMessage = "Ready to detect face"
@Published var currentStatus: JAAKVisageStatus = .notLoaded
@Published var recordedVideos: [RecordedVideo] = []
private(set) var configuration: JAAKVisageConfiguration
private var visageUIView: JAAKVisageUIView?
init() {
var config = JAAKVisageConfiguration()
config.videoDuration = 5.0
config.disableFaceDetection = false
config.enableInstructions = true
self.configuration = config
}
func setVisageUIView(_ view: JAAKVisageUIView) {
self.visageUIView = view
// Auto-start detection
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
view.startDetection()
}
}
func restartDetector() {
do {
try visageUIView?.restartDetector()
statusMessage = "Reinitiated successfully"
} catch {
statusMessage = "Failed to reset:\ (error.locatedDescription)"
}
}
}
// Wrapper to use UIKit in SwiftIU
struct VisageViewWrapper: UIViewRepresentable {
let manager: VisageManager
func makeUIView(context: Context) -> JAAKVisageUIView {
let view = JAAKVisageUIView()
view.backgroundColor = UIColor.black
manager.setVisageUIView(view)
return view
}
func updateUIView(_ uiView: JAAKVisageUIView, context: Context) {
if !uiView.isSetup {
let detector = JAAKVisageSDK(configuration: manager.configuration)
detector.delegate = manager
let previewView = detector.createPreviewView()
uiView.addSubview(previewView)
previewView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
previewView.topAnchor.constraint(equalTo: uiView.topAnchor),
previewView.leadingAnchor.constraint(equalTo: uiView.leadingAnchor),
previewView.trailingAnchor.constraint(equalTo: uiView.trailingAnchor),
previewView.bottomAnchor.constraint(equalTo: uiView.bottomAnchor)
])
uiView.faceDetector = detector
uiView.previewView = previewView
uiView.isSetup = true
}
}
}
// Extension of manager as delegate
extension VisageManager: JAAKVisageSDKDelegate {
func faceDetector(_ detector: JAAKVisageSDK, didUpdateStatus status: JAAKVisageStatus) {
DispatchQueue.main.async {
self.currentStatus = status
self.statusMessage = "Estado: \(status.rawValue)"
}
}
func faceDetector(_ detector: JAAKVisageSDK, didCaptureFile result: JAAKFileResult) {
DispatchQueue.main.async {
// Almacenar video grabado
let video = RecordedVideo(
fileName: result.fileName ?? "video_\(Date().timeIntervalSince1970).mp4",
data: result.data,
recordedAt: Date(),
size: result.fileSize
)
self.recordedVideos.append(video)
self.statusMessage = "Video capturado: \(result.fileName ?? "desconocido")"
}
}
func faceDetector(_ detector: JAAKVisageSDK, didEncounterError error: JAAKVisageError) {
DispatchQueue.main.async {
self.statusMessage = "Error:\ (error.locatedDescription)"
}
}
func faceDetector(_ detector: JAAKVisageSDK, didDetectFace message: JAAKFaceDetectionMessage) {
if message.faceExists && message.correctPosition {
DispatchQueue.main.async {
self.statusMessage = "Retiring face"
}
}
}
}
// Structure for video engraving
struct RecordedVideo: Identifiable {
let id = UUID()
let fileName: String
let data: Data
let recordedAt: Date
let size: Int
var formattedDate: String {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter.string(from: recordedAt)
}
var sizeString: String {
return ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file)
}
}
// Simplified video view
struct VideoRowView: View {
let video: RecordedVideo
@State private var showingPlayer = false
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
VStack(alignment: .leading) {
Text(video.fileName)
.font(.subheadline)
.fontWeight(.medium)
Text("Size:\ (video .sizeString)")
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
Button("Reproducir") {
showingPlayer = true
}
.font(.caption)
.foregroundColor(.white)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(Color.blue)
.cornerRadius(6)
}
.padding()
.background(Color(.systemGray6))
.cornerRadius(8)
// Basic player
if showingPlayer {
if #available(iOS 14.0, *) {
SimpleVideoPlayer(videoData: video.data)
.frame(height: 200)
.cornerRadius(8)
.padding()
}
Button("Cerrar") {
showingPlayer = false
}
.font(.caption)
.foregroundColor(.white)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(Color.red)
.cornerRadius(8)
}
}
}
}
@available(iOS 14.0, *)
struct SimpleVideoPlayer: View {
let videoData: Data
@State private var player: AVPlayer?
var body: some View {
Group {
if let player = player {
VideoPlayer(player: player)
.cornerRadius(8)
} else {
Rectangle()
.fill(Color.black)
.overlay(
ProgressView("Cargando video...")
.foregroundColor(.white)
)
.cornerRadius(8)
}
}
.onAppear {
setupPlayer()
}
.onDisappear {
cleanup()
}
}
private func setupPlayer() {
let tempDir = FileManager.default.temporaryDirectory
let tempURL = tempDir.appendingPathComponent(UUID().uuidString).appendingPathExtension("mp4")
do {
try videoData.write(to: tempURL)
player = AVPlayer(url: tempURL)
} catch {
print("Error:\ (error)")
}
}
private func cleanup() {
player?.pause()
player = nil
}
}
Passage 3: Configure Camera Permissions
Objective
Configure camera permissions required by iOS correctly.
3.1 Info.pist
Method 1 - Modern Xcode (recommended):
- Select your target at Xcode
- Go to the tab "Info"
- In "Custom iOS Target Properties," click "+"
- Search and select "Privacy - Camera Usage Description"
- Add the description: "That application needs access to the camera to detect faces"
Method 2 - Info.pist file (alternative):
<key>NSCameraUsageDescription</key>
<string>Esta aplicación necesita acceso a la cámara para detectar rostros</string>
3.2 Management of Code Permises
import AVFoundation
class PermissionsManager {
static func checkCameraPermission() -> AVAuthorizationStatus {
return AVCaptureDevice.authorizationStatus(for: .video)
}
static func requestCameraPermission(completion: @escaping (Bool) -> Void) {
AVCaptureDevice.requestAccess(for: .video) { granted in
DispatchQueue.main.async {
completion(granted)
}
}
}
static func openSettings() {
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl)
}
}
}
3.3 Monitoring Before Detection
private func checkPermissionsAndStart() {
let cameraStatus = PermissionsManager.checkCameraPermission()
switch cameraStatus {
case .authorized:
startDetection()
case .notDetermined:
PermissionsManager.requestCameraPermission { granted in
if granted {
self.startDetection()
} else {
self.showPermissionAlert()
}
}
case .denied, .restricted:
showPermissionAlert()
@unknown default:
showPermissionAlert()
}
}
private func showPermissionAlert() {
let alert = UIAlertController(
title: "Camera permits",
message: "Access to camera required for facial detection",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "Configure", style: .default) { _ in
PermissionsManager.openSettings()
})
alert.addAction(UIAlertAction(title: "Cancelar", style: .cancel))
present(alert, animated: true)
}
Track 4: Record and Archives Management
Objective
Implement complete management of recorded videos and file processing.
4.1 Response architecture
JAAKFileResult:
public struct JAAKFileResult {
public let data: Data // Binary information about the video
public let base64: String // Video encoded at base64
public let mimeType: String? // Tipo MIME (video/mp4)
public let fileName: String? // Name of file
public let fileSize: Int // File size in bytes
}
4.2 Videos processing
private func processVideoFile(_ fileResult: JAAKFileResult) {
print("_")
print("Name: {fileResultWhat's his name? "unknown")")
print("Size: {fileResult.filesize) bytes")
print("Tipo MIME: \(fileResult.mimeType ?? "unknown")")
// Save in local documents
saveToDocuments(fileResult)
// Convert to base64 for sending to server
let base64String = fileResult.base64
sendToServer(base64String, fileName: fileResult.fileName)
}
private func saveToDocuments(_ fileResult: JAAKFileResult) {
guard let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return
}
let fileName = fileResult.fileName ?? "face_video_\(Date().timeIntervalSince1970).mp4"
let fileURL = documentsPath.appendingPathComponent(fileName)
do {
try fileResult.data.write(to: fileURL)
print("Video saved at:\ (filefURL)")
} catch {
print("Failed saving video:\ (error)")
}
}
private func sendToServer(_ base64String: String, fileName: String?) {
let payload: [String: Any] = [
"videoData": base64String,
"fileName": fileName ?? "face_video.mp4",
"timestamp": Date().timeIntervalSince1970,
"platform": "ios",
"sdkVersion": "1.0.0"
]
print("Enviando video al servidor: \(payload.keys)")
// Implementar llamada HTTP
}
4.3 SDK
JAAKVisageStatus:
public enum JAAKVisageStatus: String, CaseIterable {
case notLoaded = "not-loaded"
case loading = "loading"
case loaded = "loaded"
case running = "running"
case recording = "recording"
case finished = "finished"
case stopped = "stopped"
case error = "error"
case faceDetected = "face-detected"
case countdown = "countdown"
case captureComplete = "capture-complete"
case processingVideo = "processing-video"
case videoReady = "video-ready"
}
Track 5: Test Facial Detection
Objective
Check that all functionalities of SDK They work properly.
checklist
| Element | State | Description |
|---|---|---|
| Camera permits | ☐ | App requests and gets permission |
| Facial detection | ☐ | AI detects faces automatically |
| Automatic registration | ☐ | Reforms with face detection |
| Files generated | ☐ | Videos are saved correctly |
| Errors management | ☐ | Mistakes are handled correctly |
Test process
Step A: Test Permissions
- Install Application as a physical device
- Open Application first time
- Check request automatic permits
- Grant permits for camera
Step B: Test Detection
- Press Button "Start"
- Position face facing the camera
- To expect automatic detection (green overlay)
- Check Start automatic recording
- Review login to confirm processing
Step C: Test Functionality
- Change Camera (front / back)
- Stop and Reboot detection
- Check Files saved as document
- Test at different light conditions
- Confirm handling of errors
Debugging and Troublehooting
Check Unit Compatibility
private func checkDeviceCompatibility() {
print("=== VERIFICANDO COMPATIBILIDAD ===")
let cameraStatus = PermissionsManager.checkCameraPermission()
print("Camera status:\ (cameraStatus)")
let systemVersion = UIDevice.current.systemVersion
print("IOS version:\ (systemVersion)")
let deviceModel = UIDevice.current.model
print("Modelo dispositivo: \(deviceModel)")
}
private func enableDebugMode() {
var config = configuration!
config.enableInstructions = true
// Apply configuration with activated debug
detector = JAAKVisageSDK(configuration: config)
}
Common problems
| Problem | Resolution |
|---|---|
| "Models Do Not Load" | Check online and memory available |
| "Camera doesn't start." | Check permits and that are not busy |
| "No face detectors." | Enhance light and face position |
| "Record Failed" | Check available storage space |
Full reference
Methods SDK
| Method | Description | Example |
|---|---|---|
| JAAKVisageSDK (configuration:) | Building SDK | JAAKVisageSDK(configuration: config) |
| startDetection () | Begins facial detection | try detector.startDetection() |
| stopDetection () | Stopped detection | detector.stopDetection() |
| restart | Reboot detector | try detector.restartDetection() |
| createPreviewView () | Create preview view | detector.createPreviewView() |
Available
| Configure | Description | When to use |
|---|---|---|
| video | Record duration in seconds | Filling as required |
| FaceDetection | Unable facial detection | For manual recording |
| enableInstructions | Show user instructions | For new users |
| cameraPosition | Initial camera position | as required |
Response structure
| Field | Description | When it's generated |
|---|---|---|
| data | Binary information about the video | Always |
| base64 | Video encoded at base64 | To send to server |
| filesName | Suggested name of file | When specified |
| filesize | File size in bytes | Always |
| mimeType | MIME type of video | Always (video / mp4) |
Problem solving
Problem: "ML model error"
// Check before use
private func preloadModelsIfNeeded() {
// The models are loaded automatically
// Check status with delegate
}
private func handleModelLoadingError() {
statusLabel.text = "Failed with models. Reboot the app."
}
Problem: "Detection doesn't work in simulator"
// It only works on a physical device
#if targetEnvironment(simulator)
showAlert(title: "Simulador",
message: "Facial detection requires a physical device")
return
#endif
Problem: "Videos aren't saved"
// Check storage permits
private func checkStoragePermissions() {
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
if documentsPath == nil {
print("Documents cannot be accessed")
return
}
print("Directory available:\ (documentsPath!)")
}
Problem: "compilation error with User Sandboxing Script"
// Building Settings
// 1. Select target
// 2. Build Settings
// 3. Buscar "User Script Sandboxing"
// 4. Cambiar a "No"
Best Practices
Using SDK
- Lighting: It works best with good front light
- Distance: face should be about 30 cm from camera
- Guidance: It works best with focused and vertical face
- Stability: Avoid abrupt movements during recording
Integration
- Threading: All callbacks run on the main thread
- Memory: The SDK automatically manages memory but monitoring use on old devices
- Cleaning: Implement automatic cleaning of temporary files
- Lifecycle: Stop detection while pausing the app to preserve battery
Security
- Permissions: Just require necessary permits (required camera)
- Data: The videos are processed locally and aren't automatically sent to servers
- Privacy: To clear the user about using the camera
- Storage: Do not store videos permanently without explicit consent
Do you need some help?
Support information
- Problem description: What are you trying to figure out?
- Xcode's logs: Screenshots of console errors
- Unit information: IOS model, version, memory
- Configure SDK: Parameters used
- Conditions of use: Lighting, distance, direction
Support Contact
Email: support Always include: IOS logo, configuration, version SDK
You have successfully implemented JAAKVisage SDK Your app can now detect faces and record videos automatically using artificial intelligence, generating optimized files for biometric monitoring processes.