Android SDK for KYC
Library for integrating KYC procedures (document and selfie identification), device data collection, and biometric element display in Android applications.
Requirements
- Minimum SDK: 21 (Android 5.0)
- Target SDK: 34 (Android 14)
- Kotlin: 1.8+
- Gradle: 7.0+
Installation
Via Maven Central
Add to your module's build.gradle file:
dependencies {
implementation("com.covery.sdk:cvr-sdk:x.y.z")
}
Permissions
The SDK requires several permissions to function properly. Add these to your AndroidManifest.xml:
Required Permissions
Camera & Hardware:
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Network & Connectivity:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
Optional Permissions
Permissions for fingerprinting:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
Note: Camera permissions are required for document and selfie capture. Network permissions are needed for data transmission. Other permissions are optional and depend on your specific use case.
Quick Start
1. Initialize SDK
When to initialize: You can initialize the SDK at the most convenient point for your app:
Application.onCreate()— app-wide early initializationActivity.onCreate()— when used only in specific activitiesFragment.onCreate()/onViewCreated()/onCreateView()— when usage is scoped to a fragment
Idempotency: It is safe to call init() multiple times. The SDK is idempotent for the same token and updates internal state if the token changes (e.g., user switch). Recommended practice is to initialize once per active token/session.
Just‑in‑time init: You may call init() right before first use of any SDK feature (e.g., before prepareKYCProcedure, showKYC, or sendDeviceData). Ensure init() completes before invoking other SDK methods.
val token = "Bearer your_token_here"
SDKCovery.init(
context = applicationContext, // Use Context instead of Activity
token = token,
) { sdkEvent ->
Log.d("SDK", "Event: $sdkEvent")
}
Note: You can use either
ContextorActivityfor initialization. UsingContextis more flexible but requires the SDK to handle Activity launching internally.
2. Prepare KYC Flow
Purpose: This method checks if the SDK is ready to perform KYC operations:
- Validates token and configuration
- Loads required ML models
- Initializes camera and hardware components
- Returns
trueif ready,falseif there are issues
Option A: Synchronous (Coroutine-based):
val isPrepared = SDKCovery.prepareKYCProcedure(
steps = listOf(KYCStepType.DOCUMENT, KYCStepType.SELFIE)
)
if (!isPrepared) {
// Handle preparation failure
Log.e("SDK", "KYC preparation failed")
// Check SDK events for specific error details
return
}
Option B: Asynchronous (Callback-based): For projects that don’t use Kotlin coroutines, the SDK also provides a callback-based wrapper:
SDKCovery.prepareKYCProcedureAsync(
steps = listOf(KYCStepType.DOCUMENT, KYCStepType.SELFIE)
) { isPrepared ->
if (!isPrepared) {
Log.e("SDK", "KYC preparation failed")
// Check SDK events for specific error details
return@prepareKYCProcedureAsync
}
// Continue with KYC flow
}
3. Start KYC Flow
Important: The SDK manages all UI logic internally using its own Activity. No need to handle fragments, FragmentManager, or custom UI components. Return the instance of activity.
Option A: Synchronous (Coroutine-based)
SDKCovery.showKYC(
context = applicationContext, // Pass Application context
flow = CoveryFlowType.FULL,
validationsSettings = ValidationsSettings.createDefaultDocumentSettings(),
eventDelay = 1000,
borderDelay = 1000
) { event ->
Log.d("SDK", "KYC Event: $event")
}
Option B: Asynchronous (Callback-based) For apps that don’t use coroutines, you can use the async wrapper:
SDKCovery.showKYCAsync(
context = applicationContext,
flow = CoveryFlowType.FULL,
validationsSettings = ValidationsSettings.createDefaultDocumentSettings(),
eventDelay = 1000,
borderDelay = 1000,
flowEvent = { event -> }
) { activity -> }
Note: The SDK automatically adds the
FLAG_ACTIVITY_NEW_TASKflag to properly launch the Activity from a non-Activity context.
4. Device Data Collection (Optional)
Note: This operation is fully managed by the SDK. No need to handle coroutines or async operations in your app.
Option A: Synchronous (Coroutine-based)
SDKCovery.sendDeviceData(applicationContext, token).collect {
when (result) {
is NetworkResult.Success -> Log.d("SDK", "Device data sent: ${result.data}")
is NetworkResult.Error -> Log.e("SDK", "Error: ${result.message}")
is NetworkResult.Loading -> Log.d("SDK", "Sending device data...")
}
}
Option B: Asynchronous (Callback-based) If you prefer a callback approach:
SDKCovery.sendDeviceDataAsync(
context = applicationContext,
token = token
) { result ->
when (result) {
is NetworkResult.Success -> Log.d("SDK", "Device data sent: ${result.data}")
is NetworkResult.Error -> Log.e("SDK", "Error: ${result.message}")
is NetworkResult.Loading -> Log.d("SDK", "Sending device data...")
}
}
Customization
The SDK supports extensive customization of themes, colors, icons, fonts, and localization.
Override Colors
<!-- app/src/main/res/values/colors.xml -->
<resources>
<!-- Selfie oval frame color -->
<color name="covery_oval_border">#FF6B35</color>
<!-- Button colors -->
<color name="covery_apply_background_color_button">#FF6B35</color>
<color name="covery_retake_background_color_button">#00FFFFFF</color>
<color name="covery_apply_icon_color_button">#FFFFFF</color>
<color name="covery_retake_icon_color_button">#FF6B35</color>
<color name="covery_apply_text_color_button">#FFFFFF</color>
<color name="covery_retake_text_color_button">#FF6B35</color>
<color name="covery_apply_stroke_color_button">#FF6B35</color>
<color name="covery_retake_stroke_color_button">#FF6B35</color>
<!-- Icon and background colors -->
<color name="covery_back_icon_color">#FF6B35</color>
<color name="covery_loading_overlay_bg_color">#B3000000</color>
<color name="covery_loading_overlay_color">#FFFFFF</color>
<!-- and others in default resource file-->
</resources>
Override Themes
<!-- app/src/main/res/values/themes.xml -->
<resources>
<style name="covery_theme" parent="covery_base_theme_light">
<item name="colorPrimary">@color/my_brand_primary</item>
<item name="colorOnPrimary">@color/my_on_primary</item>
<item name="colorAccent">@color/my_accent</item>
</style>
<style name="covery_text_theme" parent="covery_theme">
<item name="android:fontFamily">@font/arial</item>
<item name="android:textSize">14sp</item>
<!-- and others in default resource file-->
</style>
</resources>
Override Localization
<!-- app/src/main/res/values-uk/strings.xml -->
<resources>
<string name="covery_face_detection_title">Take a face photo</string>
<string name="covery_face_result_title">Identity verification</string>
<string name="covery_face_result_accept_button_text">Confirm photo</string>
<string name="covery_face_result_retake_button_text">Retake photo</string>
<!-- and others in default resource file-->
</resources>
Override Icons
<!-- app/src/main/res/values/themes.xml -->
<resources>
<style name="covery_apply_button_theme" parent="Widget.Material3.Button.OutlinedButton.Icon">
<item name="icon">@drawable/my_apply_icon</item>
</style>
<style name="covery_retake_button_theme" parent="Widget.Material3.Button.OutlinedButton.Icon">
<item name="icon">@drawable/my_retake_icon</item>
</style>
<!-- and others in default resource file-->
</resources>
Events
The SDK provides comprehensive event tracking for monitoring KYC flow progress and user interactions.
General Events
TOKEN_IS_NULL— token not provided or invalidFLOW_IS_COMPLETED— KYC flow completed
Selfie Events
PHOTO_IS_SENT— selfie successfully sentPHOTO_IS_CREATING— selfie creation in progressPHOTO_IS_CREATED— selfie createdTOO_DARK_IMAGE— image too darkTOO_BRIGHT_IMAGE— image too brightIMAGE_IS_NOT_SHARPED— image blurredIMAGE_HAVE_HARD_SHADOW— strong shadow on imageSELFIE_CLOSED_EYES— eyes closedSELFIE_HEAD_ROTATION— head turnedSELFIE_MANY_FACES— multiple faces in frameSELFIE_NO_FACE_FOUND— no face detectedSELFIE_FACE_IS_TOO_FAR— face too farSELFIE_FACE_IS_TOO_CLOSE— face too closeSELFIE_DONT_MOVE— user not movingSELFIE_DEVICE_ORIENTATION— incorrect device orientationSELFIE_FACE_IS_NOT_CENTERED— face not centered
Document Events
DOCUMENT_ABSENT— document not detectedDOCUMENT_IS_NOT_CENTERED— document not centeredEVENT_DOCUMENT_DEVICE_ORIENTATION— incorrect device orientationEVENT_TOO_DARK_IMAGE— image too darkEVENT_TOO_BRIGHT_IMAGE— image too brightEVENT_DOCUMENT_NOT_FOUND— document not foundEVENT_IMAGE_IS_NOT_SHARP— image blurredEVENT_DOCUMENT_HARD_SHADOW— strong shadowEVENT_DOCUMENT_ROTATION— document rotationEVENT_DOCUMENT_IS_TOO_FAR— document too farEVENT_DOCUMENT_IS_TOO_CLOSE— document too closeEVENT_DOCUMENT_NOT_EXPECTED— unexpected document typeEVENT_DOCUMENT_DONT_MOVE— document not moving
Additional Features
Touch Tracking (Optional)
Capture user interactions for behavioral analysis:
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
SDKCovery.getTouchEvent(event)
return super.dispatchTouchEvent(event)
}
Fingerprint View (Optional)
Send the generated fingerprint to Covery. The lambda provides the main activity instance used by the SDK:
SDKCovery.showCoveryFingerprint(
context = applicationContext // Pass Context
) { activity ->
Log.d("SDK", "main activity of fragment: $activity")
}
Finish and Cleanup
Purpose: Clear session data and free resources after SDK usage.
When to use:
- When the user logs out of your application
- Before closing the app completely
- When switching between different user sessions
- To free up memory and storage resources
What it does:
- Finish inner activity
- Clears cached images and temporary files
- Resets SDK internal state
- Releases camera and hardware resources
- Clears user session data
// Call when you're done with the SDK
SDKCovery.clearData()
Important: Always call
clearData()when you're finished using the SDK to prevent memory leaks and ensure proper resource cleanup.
Important Notes
Resource Naming
- All SDK resources have the
coveryprefix (e.g.,covery_button_background,covery_text_title) - This prevents naming conflicts with your app's resources
- Never override SDK resources without the proper prefix
Threading & Coroutines
- The
showKYC()method must be called from the main thread (Dispatchers.Main) - All coroutines and async operations are managed internally by the SDK
- Your app doesn't need to handle coroutines or async logic
Architecture
- The SDK uses its own Activity for all UI operations - no fragments, FragmentManager, or custom UI components needed
- Context-based initialization - use
Contextinstead ofActivityfor better encapsulation - Fully self-contained - the SDK manages all its own lifecycle and resources
- No external Activity dependencies - the SDK launches its own Activity internally
ProGuard/R8
No additional ProGuard rules are required. Consumer rules are automatically applied from the AAR.
Theme Support
The SDK supports both light and dark themes and automatically adapts to your app's theme configuration.
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
iOS SDK for KYC
Requirements
- macOS (minimum version 15.1.1) [link]
- Xcode (minimum version 16.1) [link]
- Ruby (minumum version 2.6.10p210) [link]
- CocoaPods (minimum version 1.15.2) [link]
- Shell zsh x86_64-apple-darwin24.0 (minimum version 5.9, it is a default shell for recent versions of macOS)
- iOS (minimum deployment target 15.5)
Installation
There are two approaches how to add CoverySDK to a project: Cocoapods or SPM.
Cocoapods package manager
First of all, set up Cocoapods for you project if it hasn't been set up before. [link]
Add to Podfile this lines of code:
pod 'CoverySDK', :tag => '1.0.0', :git => 'https://github.com/coverydevteam/ios-sdk.git'
pod 'TensorFlowLiteSwift'
In a terminal, go to the root of the project where is located Podfile and run the command:
Swift Package Manager
zsh
pod install
Swift Package Manager
Also there is an option to install CoverySDK via SPM, but you should keep in mind that the dependency TensorFlowLiteSwift currently can be installed only via Cocoapods:
dependencies: [
.package(url: "https://github.com/coverydevteam/ios-sdk.git", .upToNextMajor(from: "1.0.0"))
]
Preparation
Before starting using SDK, an app should request a permission to a camera access. App's Info.plist should contain a key NSCameraUsageDescription. Otherwise SDK should work inproperly. This means that the app should ask the permission before and only after that should start showing screens from SDK.
For example:
<key>NSCameraUsageDescription</key>
<string>Required for document and face capture</string>
Note: All methods below may return their callbacks in non-main thread.
Customization
When an app launches, SDK should be configured at first time:
do {
try SDKCovery.configure(config: nil)
} catch {
debugPrint(error.localizedDescription)
}
There is information about a configuration object:
/// A configuration object which can be used for SDK initialization
final public class SDKConfiguration {
/// Positioning of Accept / Retake buttons
/// - horizontal:
/// * [ Accept ] [ Retake ]
/// - vertical:
/// * [ Accept ]
/// * [ Retake ]
public enum ButtonsBarAxis : String, Codable {
case horizontal
case vertical
}
/// Configuration object for text
public struct TextConfigurationItem : Codable {
/// Initializes a configuration object
/// - Parameters:
/// - fontName: Custom font name. The given font should be exist in the app. If font name isn't set then default one will be used
/// - fontSize: Custom font size. If font size isn't set then default one will be used
public init(fontName: String? = nil, fontSize: CGFloat? = nil)
}
/// Configuration object for button
public struct ButtonConfigurationItem : Codable {
public enum ButtonType : String, Codable {
case flat
case bordered
}
/// Initializes a configuration object
/// - Parameters:
/// - showsIcon: A flag for showing/hiding a button icon. If it is `nil` then default value will be used
/// - buttonType: Defines a view of a button. if it is `nil` then default value will be used
/// - buttonBorderCornerRadius: A button corner radius in points. If it is `nil` then default value will be used
/// - borderWidth: A border width in points. If it is `nil` then default value will be used
public init(showsIcon: Bool? = nil, buttonType: CoverySDK.SDKConfiguration.ButtonConfigurationItem.ButtonType? = nil, buttonBorderCornerRadius: CGFloat? = nil, borderWidth: CGFloat? = nil)
}
/// Configuration object for button's bar
public struct ButtonsBarConfiguration : Codable {
public enum ButtonOrder : String, Codable {
case accept
case retake
}
/// Initializes a configuration object
/// - Parameters:
/// - layoutAxis: Positioning of Accept / Retake buttons
/// - buttonOrder: An order of buttons (Accept | Retake or Retake | Accept)
/// - retakeButton: A cuztomization of Retake button
/// - acceptButton: A customization of Accept button
/// - titleFont: A customization of title font
/// - bodyFont: A customization of body font
public init(layoutAxis: CoverySDK.SDKConfiguration.ButtonsBarAxis? = nil, buttonOrder: CoverySDK.SDKConfiguration.ButtonsBarConfiguration.ButtonOrder? = nil, retakeButton: CoverySDK.SDKConfiguration.ButtonConfigurationItem? = nil, acceptButton: CoverySDK.SDKConfiguration.ButtonConfigurationItem? = nil, titleFont: CoverySDK.SDKConfiguration.TextConfigurationItem? = nil, bodyFont: CoverySDK.SDKConfiguration.TextConfigurationItem? = nil)
}
/// Initializes button's bar configurations
/// - Parameters:
/// - buttonBarConfiguration: Object for button's bar
/// - localizationTableName: Name of custom localization file
public init(buttonBarConfiguration: CoverySDK.SDKConfiguration.ButtonsBarConfiguration? = nil, localizationTableName: String? = nil)
}
Sample of localization file for SDK is in Localizable_sample.xcstrings. If you need to add your own localizations, you shold create .strings or .xcstrings file(s) and pass the name of it to SDK during initialization. Current version SDK supports only English localization. In case of altering localization, own variant of English version should be also provided.
In order to customize a theme of SDK's screens you should create a specific folder structure in your image assets:
- covery_sdk
- selfie
- colors
- accept_background
- accept_button_background
- accept_button_border
- accept_button_icon
- accept_button_text
- accept_text
- back_button
- oval_border_selected
- retake_button_background
- retake_button_border
- retake_button_icon
- retake_button_text
- scanner_text
- icons
- accept_button
- retake_button
- colors
- selfie

Please don't forget to set a checkmark for a namespace to every folder, otherwise the colours couldn't be get properly by SDK.

Finally, you can alter the default SDK fonts with custom ones. They should be properly installed into the app bundle in order to be used by SDK with custom names.
Initialization
After obtaining an access token from Covery web-service, SDK should be initialized:
DKCovery.Authorization.updateToken(<access token from backend>) { error in
debugPrint("Error: \(error?.localizedDescription)")
}
Usage of SDK
Selfie KYC
After initializing SDK with access token, there is method to initiate selfie KYC procedure:
SDKCovery.KYC.startKYCSelfie { error in
debugPrint("Error: \(error?.localizedDescription)")
}
Showing KYC scanner UI
When the previous method completes without any error, the next step is showing a screen of KYC scanner.
SDKCovery.UIController.showKYC(
parentController: <parent controller>) {
// User cancel completion
}
serverCompletion: { (result, error) in
...
} cameraCompletion: { error in
debugPrint("Error: \(error.localizedDescription)")
}
Alternative method for using in SwiftUI is:
struct CustomView: View {
@State private var showsCamera: Bool = false
var body: some View {
ZStack {
...
someSwiftUIView.showCoveryKYC(
showingController: $showsCamera,
cancelCompletion: {
...
},
serverCompletion: { result in
debugPrint(result)
switch result {
case .success(let success):
...
case .failure(let error):
debugPrint("Camera error: \(error.localizedDescription)")
}
},
cameraCompletion: { error in
debugPrint("Camera error: \(error.localizedDescription)")
})
}
}
}
After finishing procedure of selfie KYC, a screen, provided by SDK is closed automatically. The response should be returned to either completion serverCompletion or completion cameraCompletion.
Document KYC
Document KYC procedure is a slightly longer. Firstly, an app should obtain a list of available documents:
SDKCovery.KYC.fetchDocumentList { result in
switch result {
case .success(let documents):
...
case .failure(let error):
debugPrint("Camera error: \(error.localizedDescription)")
}
}
Note: SDK doesn't provide any UI to represent list of documents, so it is a responsibility of an app. After choosing a specific document type and document name by user, there is a method of initiation document KYC procedure:
let documentId = ... // Choosed by user
let documentType = ... // Choosed by user
// Name (probably localized version) of choosed document by user. Provided by an app.
// Can be **nil**. If this field isn't set, the default name of the document will be applied.
let documentName = ...
SDKCovery.KYC.startKYCDocument(
documentId: documentId, documentType: documentType, documentName: documentName
) { error in
...
}
Finally, an app performs method of showing KYC scanner.
Device Data
There is one more method in SDK. It is used for sending a device data to the backend:
SDKCovery.DataCollection.sendDeviceData { result in
...
}
SDK error list
Also SDK provides list of predefined errors:
public enum SDKError: Error {
/// Informs that the SDK has been used before initialization
case isntInitialized
/// A user hasn't allowed yet or has forbidden a camera permission
case cameraPermission
/// There is happened a video session creation error
case videoSessionCreation
/// There is no enough free space on the device
case notEnoughDiskSpace
/// Covery access token is expired
case authorizationError
/// Incorrect response from Covery service
case incorrectResponse
/// A given document id isn't found or incorrect
case incorrectDocumentId
/// Some internal SDK error occurs
case internalSDKError
/// Some network error occurs (e. g. backend error)
case networkError
/// An error which is caused by an Internet connection issue
case internetConnectionError
}