Release notes, Releases Cordova SDK

Migration Guide

Migration to 4.10.0

4.10.0 contains breaking changes: most of them make Android and iOS return the same result and error shapes. Find the APIs you use below and skip the rest.

API Android iOS What you need to do
Installation ✅ Reinstall the iOS platform
getUserScore() ✅ ✅ Read the new result object, update error checks
faceMatch() ✅ ✅ Update result field names and error handling
startWorkflow() ✅ ✅ Read error.message instead of a string
approve module result ✅ ✅ Rename approveData keys
Phone, Email, FullName modules ✅ ✅ Rename addPhone and addEmail, check for missing values
setTheme() ✅ Rename positive800 to positive750

Installation

iOS. The plugin now depends on the IncodeBridgeCommon pod. It's declared by the plugin, so your app needs no source change, but the pod must be resolved. After updating the plugin, reinstall the iOS platform, or re-run pod install in platforms/ios if you've made manual changes there:

cordova platform rm ios
cordova platform add ios

getUserScore()

One Result Object on Both Platforms

Previously, Android returned a JSON string, and iOS returned an object nested under userScoreData.data. The keys were different. Now, both platforms return the same top-level object:

{
  "extendedUserScoreJsonData": "<raw JSON>",
  "overall": { "value": "80.5", "status": "ok" },
  "idValidation":         { "overall": { … }, "photoSecurityAndQuality": [ … ], "idSpecific": [ … ] },
  "liveness":             { "overall": { … }, "livenessScore": { … }, "photoQuality": "70.5" },
  "faceRecognition":      { "overall": { … }, "existingUser": false },
  "governmentValidation": { "overall": { … }, "recognitionConfidence": { … }, "validationStatus": { … }, "ocrValidation": [ … ] }
}

See Results — getUserScore for the full contract.

  cordova.exec(function (result) {
-   const score = JSON.parse(result).overallScore;              // Android: "80.5/100"
-   const score = result.userScoreData.data.overallScore;       // iOS
-   const faceScore = result.userScoreData.data.facialRecognitionScore;
+   const score = result.overall.value;                         // "80.5" on both
+   const status = result.overall.status;
+   const faceScore = result.faceRecognition?.overall?.value;
  }, onError, "Cplugin", "getUserScore", ["accurate"]);

What changed in the values:

Before Now
Android payload JSON string, needed JSON.parse() Object; remove JSON.parse()
Android score values "80.5/100", sometimes a localized phrase "80.5", also in onUserScoreFetched
iOS status warning warn (set: ok, warn, fail, unknown, manual, null)
iOS absent values "" null
iOS existingUser String "false" Boolean false

Rules to code against:

  • overall and extendedUserScoreJsonData are always present. overall.value and overall.status are null when the SDK returned no overall score.
  • idValidation, liveness, faceRecognition, and governmentValidation are present only when the SDK returned them, so guard your access. Inside a present section, every key is present and null when absent.
  • Check lists are always arrays, [] when empty. Entries with an unknown status are left out of photoSecurityAndQuality and ocrValidation; idSpecific is unfiltered.
  • extendedUserScoreJsonData is still a raw JSON string ("{}" when unavailable) and still needs JSON.parse().

When the userScore module runs as part of a flow for iOS, the { module: "userScore" } result still arrives under userScoreData, but its value is now the same object that getUserScore returns:

- const score = result.userScoreData.data.overallScore;
+ const score = result.userScoreData.overall.value;

Errors

errorCallback now receives one of these strings on both platforms:

Error Meaning
userScoreFailed Transport or HTTP failure, mapping failure, submit-only mode, or (iOS only) a completely empty score.
userCancelled The user cancelled. Android only: the call shows no UI, so iOS never reports it.
  function (error) {
-   if (error === "UserScoreFailed") { ... }   // Android
-   if (error === "onUserCancelled") { ... }   // Android
+   if (error === "userScoreFailed") { ... }
+   if (error === "userCancelled") { ... }
  }
  • iOS: Failures used to reach the success callback as { "userScoreData": { "debug": "nil" } }. If you detected them by looking for debug or a missing overall, move that handling into errorCallback.
  • Both: Submit-only mode, transport/HTTP failures and mapping failures now report userScoreFailed. Previously, Android succeeded with an empty payload. If you treated an empty success as "no score yet", handle userScoreFailed instead. One difference remains: if the server returns a completely empty score (HTTP 200), iOS reports userScoreFailed and Android succeeds with an empty result.

Behavior Changes on Android

  • "fast" is honored: Previously, Android ignored fetchMode and always fetched accurate, its default. Calls passing "fast" now get the faster fetch, which can report different scores. Pass "accurate" or omit fetchMode to keep the old behavior.
  • No remembered interviewId: Previously, Android reused the interviewId of the session created earlier in the app's lifetime. Both platforms now use the current session. To score a different session, pass its interviewId as the new fourth argument:
getUserScore(onSuccess, onError, "accurate", interviewId);

You can get the interviewId from the onOnboardingSessionCreated result.

faceMatch()

These changes affect standalone faceMatch() call only. The addFaceMatch module's faceMatchData is unchanged.

Result

Change Platform Update
existingUser renamed to isExistingUser Both result.existingUser → result.isExistingUser
status removed Both Use isFaceMatched (see below)
No longer nested under faceMatchData iOS result.faceMatchData.confidence → result.confidence
Unavailable fields are left out instead of 0 / false / "" Both (iOS for isFaceMatched, isNameMatched, existingInterviewId) Check that the key is present
-1 confidence scores are left out Android confidence === -1 → confidence === undefined
- if (result.status === "match") { ... }
+ if (result.isFaceMatched === true) { ... }

- if (result.nfcVsIdConfidence > 0.8) { ... }
+ if (result.nfcVsIdConfidence !== undefined && result.nfcVsIdConfidence > 0.8) { ... }
  • Previously, status was always "match" or "mismatch". A missing isFaceMatched now means no comparison was possible, so it isn't a direct substitute.
  • A 0 confidence is still returned: it's a real "no match" score.
  • On iOS, a getUserScore() call made after faceMatch() no longer includes a faceMatchData key.

Errors

The error callback now receives { code, message, cause }. Previously, on iOS, it was never called: failures arrived at the success callback as faceMatchData: { debug: "..." }.

  function (error) {
-   if (error === "onUserCancelled") { ... }
-   if (error === "FaceMatchFailed") { ... }
+   if (error.code === "userCancelled") { ... }
+   if (error.code === "faceMatchError") { console.log(error.message); }
  }

userCancelled is Android only. iOS has no separate cancellation signal and reports faceMatchError.

startWorkflow()

The error callback now receives { code, message, cause } on both platforms, as faceMatch() does. It used to be a string: "Failed to start workflow: <message>" on Android, "No presenting view controller available." on iOS.

  function (error) {
-   console.log(error);
+   console.log(error.message);
  }

approve Module Result

The in-flow approve module's approveData now uses the same keys as the new approve() method:

- { status: "approved", id: "<uuid>", customerToken: "<token>" }
+ { success: true, uuid: "<uuid>", customerToken: "<token>", error: null }
- if (result.approveData.status === "approved") { ... }
+ if (result.approveData.success) { ... }

- const customerId = result.approveData.id;
+ const customerId = result.approveData.uuid;
  • When the SDK returns none, uuid and customerToken are null instead of "".
  • error is a flow error string (sslPinningFailed or unknown) on iOS, and always null on Android.

Phone, Email and FullName Modules

addPhone and addEmail Renamed

- { module: "addPhone" }
+ { module: "Phone" }

- { module: "addEmail", otpVerificationEnabled: "true" }
+ { module: "Email", otpVerification: true }

The OTP parameter is now named otpVerification, matching the native SDK, and accepts a real boolean. The string form ("true") still works.

Empty Capture Values Omitted

phoneData.phone, emailData.email, and fullNameData.name were previously "" when the SDK captured nothing. The key is now absent instead.

- if (result.phoneData.phone !== "") { ... }
+ if (result.phoneData.phone !== undefined) { ... }

setTheme()

For Android, the theme color positive800 is renamed to positive750. It represents the same color. Android now ignores the old key and falls back to the default color, as iOS already does.

 "colorPalette": {
-  "positive800": "#0C5030"
+  "positive750": "#0C5030"
 }

Migration to 4.9.0

Update the Signature V2 title and description string overrides for Android

Signature V2 uses dedicated string resources for the title and description. V1 continues to use the existing string resources.

If you enable V2 and override the V1 strings, add these V2 overrides to your strings.xml file:

<string name="onboard_sdk_signature_capture_title">Your title</string>
<string name="onboard_sdk_signature_capture_description">Your description</string>

Keep these V1 overrides if your integration still uses V1:

<string name="onboard_sdk_signature_title">Your title</string>
<string name="onboard_sdk_signature_description">Your description</string>

No change is required if you do not override these strings.

Video Selfie V2 hides the close button on the camera steps on Android

When Video Selfie V2 is enabled for your account, its camera steps hide the close (X) button, so cordova.exec(resolve, reject, "Cplugin", "showCloseButton", ["true"]) does not apply to them. The button still shows on the other screens. Video Selfie V1 keeps the button over the camera. No code change is required. If your users rely on the close button to leave a camera step, tell them about the new behavior or keep Video Selfie V1.

MLConsentData.status now reflects the user's choice on iOS

The addMachineLearningConsent module used to report status: true on iOS whenever the submission call succeeded, even when the user declined the consent. It now reports the choice the user made: true when the consent was accepted and false when it was declined. The consent stays optional and the flow continues in both cases. If your app treats MLConsentData.status as submitted, update it to treat false as declined instead of as a module failure.

A mandatory Combined Consent that has no readable text or checkbox ID can no longer be silently accepted on iOS. The module ends and the flow stops, so startOnboarding() and startOnboardingSection() call the errorCallback with the new "combinedConsentsNotReceived" string. Text that is empty or only spaces counts as missing text. Give the consent text in Dashboard to clear the error. Optional consents that cannot be shown are still left out and the flow continues, as before.

Handle it alongside the other typed flow errors:

  function (error) {
    switch (error) {
      case "permissionsDenied":
        break;
+     case "combinedConsentsNotReceived":
+       // A mandatory combined consent is misconfigured in Dashboard.
+       break;
      default:
        break;
    }
  }

Migration to 4.8.0

setFaceAuthenticationHint argument renamed to identityId

The argument is the expected identity ID, not on-screen hint copy:

- setFaceAuthenticationHint(success, error, faceAuthenticationHint)
+ setFaceAuthenticationHint(success, error, identityId)

  cordova.exec(success, error, "Cplugin", "setFaceAuthenticationHint", [
-   "Look at the camera",
+   "customer@example.com",
  ]);

setUXConfig argument renamed to jsonConfig

- setUXConfig(success, error, config)
+ setUXConfig(success, error, jsonConfig)

  cordova.exec(success, error, "Cplugin", "setUXConfig", [
    JSON.stringify({ showFooter: false }),
  ]);

The value is still a JSON string. Only the parameter name changed.

initializeSDK() method parameter isExternalTokenEnabled removed

External tokens belong on sessionConfig.token. Remove the argument and shift subsequent positional args:

cordova.exec(success, error, "Cplugin", "initializeSDK", [
  apiKey,
  apiUrl,
  loggingEnabled,
  testMode,
- "true",                 // isExternalTokenEnabled — removed
  clientExperimentId,
  e2eeUrl,
  sslPinningConfig,
+ "standard",             // sdkMode (optional)
+ "false",                // externalAnalyticsEnabled (optional)
+ "false",                // externalScreenshotsEnabled (optional)
]);

initializeSDK error payload format

Init failures now return "<code>: <message>" on both iOS and Android platforms:

- if (err === "configError") { ... }
+ if (typeof err === "string" && err.indexOf("configError") === 0) { ... }

Android build requirements raised

This release updates the underlying Android SDK to 5.51.0, which raises the minimum Android toolchain your app must build with. There are no JavaScript API changes; all of the work is in your Android build configuration.

Update the android platform preferences in your app's config.xml:

<platform name="android">
-  <preference name="android-compileSdkVersion" value="35" />
+  <preference name="android-compileSdkVersion" value="36" />
+  <preference name="AndroidGradlePluginVersion" value="8.9.1" />
+  <preference name="GradleVersion" value="8.14.5" />
   <preference name="GradlePluginKotlinEnabled" value="true" />
-  <preference name="GradlePluginKotlinVersion" value="1.8.21" />
+  <preference name="GradlePluginKotlinVersion" value="2.2.21" />
</platform>
Requirement Minimum Reason
compileSdk 36 Required by the SDK's updated CameraX and Kotlin dependencies.
Android Gradle Plugin 8.9.1 Required to build against compileSdk 36.
Gradle 8.14.5 AGP 8.9.1 is validated against Gradle 8.14.5 for this SDK release.
Kotlin Gradle plugin 2.2.21 The SDK is compiled with Kotlin 2.2.21; any module compiling Kotlin source with the SDK on its classpath must be able to read its Kotlin metadata.
kotlinx-coroutines 1.9.0 Required by CameraX 1.6.1. Pulled in transitively; only act if you have explicitly pinned an older version.
JDK (to run Gradle) 17 Required by AGP 8.9.1. The compiled Java source/target level stays at 11.

Pure-Java Cordova apps still need the Kotlin plugin bump. The plugin itself contains Kotlin sources that are compiled with the SDK on the classpath.

Info

The preference key that cordova-android reads is AndroidGradlePluginVersion. If your config.xml uses android-gradlePluginVersion, it is silently ignored and you will keep building with the platform's default AGP. Rename it.

OkHttp packaging exclusion: handled by the plugin

OkHttp/logging-interceptor 5.3.2 and its transitive JSpecify dependency both ship an identical OSGi manifest at META-INF/versions/9/OSGI-INF/MANIFEST.MF, which fails APK packaging with a duplicate-resource error. The plugin now declares this exclusion in its own Gradle configuration, so no action is required in a standard Cordova integration.

If your build overrides packaging options in a way that drops the plugin's configuration, add the exclusion yourself in platforms/android/app/build-extras.gradle:

android {
    packaging {
        resources {
            excludes += ['META-INF/versions/9/OSGI-INF/MANIFEST.MF']
        }
    }
}

Compose Material3 : Compose minimum versions raised

The SDK's Compose-based screens are now built against Compose Material3 1.4.0 and Compose 1.8.0. Cordova apps do not normally resolve Compose directly, so most integrations need no action. Act only if you or another Cordova plugin explicitly pin these libraries below those versions. An older resolved set crashes at runtime (NoSuchMethodError / NoClassDefFoundError in androidx.compose.*) when a Compose screen opens.

Migration to 4.7.0

initializeSDK() method parameter disableJailbreakDetection removed

The disableJailbreakDetection parameter has been removed from the initializeSDK() method. It has no replacement. If you previously set it, remove it and update your positional arguments.

Removed deprecated setCommonConfig() method.

The deprecated setCommonConfig() method that displayed or hid the close button has been removed. Use showCloseButton() instead.

Migration to 4.6.0

Renamed neutral and black color palette tokens on Android

The neutral and black keys in theme's colorPalette have been renamed:

  • neutral -> neutralLight
  • black -> neutralDark

If you provided the theme via a JSON config, rename the keys inside colorPalette:

"colorPalette": {
+  "neutralLight": "#ffffff",
-  "neutral": "#ffffff",
+  "neutralDark": "#000000",
-  "black": "#000000",
  "brand50": "#e5f0ff",
  ...
  "positive500": "#189F60",
  "positive600": "#189F60",
  "positive800": "#0C5030"
}

Theme JSON that still uses the old neutral and black keys will silently fall back to the defaults #FFFFFF and #000000, because unknown keys are ignored during parsing. Update your JSON to use the new keys to keep your customizations applied.

Migration to 4.5.0

Changed default value for mask check in SelfieScan module

The default value for the maskCheckEnabled parameter in the addSelfieScan module has been changed from false to true. If you did not previously configure this flag, face mask validation will now be enforced by default during face capture. To preserve the previous behavior, explicitly disable these flags:

{ module: "addSelfieScan", maskCheckEnabled: "false"}

Changed default values for face capture checks in FaceAuthentication module

The default values for the faceMaskCheck, headCoverCheck, lensesCheck, and eyesClosedCheck parameters in the addFaceAuthentication module have been changed from false to true. If you did not previously configure these flags, these validations will now be enforced by default during face authentication.

To preserve the previous behavior, explicitly disable these flags:

{
  module: "addFaceAuthentication",
  faceMaskCheck: "false",
  headCoverCheck: "false",
  lensesCheck: "false",
  eyesClosedCheck: "false"
}

SQLCipher attribution required if you ship an open-source licenses screen on Android

Local Room databases used by the SDK are now encrypted at rest with SQLCipher for Android, distributed under a BSD-style license. The license requires consumers that redistribute binaries, such as your application, to reproduce its copyright notice "in the documentation and/or other materials provided with the distribution".

If your application includes an "Open Source Licenses" screen, please add the SQLCipher notice listed in Licenses. No code change is needed if you do not ship such a screen.

Migration to 4.3.0

Removed localization keys on iOS

  • incdOnboarding.nameInfo.lastnamePlaceholder
  • incdOnboarding.ccv.invalidCCV

Renamed localization keys on iOS

  • incdOnboarding.email.title -> incdOnboarding.userInformation.email.title
  • incdOnboarding.email.invalidEmail -> incdOnboarding.userInformation.email.wrongFormat
  • incdOnboarding.ccv.title -> incdOnboarding.userInformation.securityCode.title
  • incdOnboarding.nameInfo.title -> incdOnboarding.userInformation.fullName.title
  • incdOnboarding.nameInfo.subtitle -> incdOnboarding.userInformation.fullName.subtitle
  • incdOnboarding.nameInfo.namePlaceholder -> incdOnboarding.userInformation.fullName.placeholder
  • incdOnboarding.nameInfo.continue -> incdOnboarding.userInformation.continue
  • incdOnboarding.ekyc.input.label.fillYourCredentials -> incdOnboarding.ekyc.input.title

Migration to 4.2.0

Updates to document chooser behavior in IdScan module

The Show document chooser screen setting in Dashboard or showIdTypeChooser in the SDK now control if the document chooser screen appears. Setting idType alone no longer hides the chooser and will be ignored.

If you previously pre-set idType (either using idType: ... in the SDK or in Dashboard) and expected the chooser to be hidden, you must now explicitly disable it or update the Flow configuration accordingly:

{
  module: "addId",
  idType: "passport",
  showIdTypeChooser: "false"
}

Android color palette changes

If you previously customized the application appearance using a config JSON:

{
    "colorPalette": {
        "negative500": "#FF5A5F",
        "negative600": "#E71111",
        "positive500": "#189F60",
        "positive600": "#189F60"
    }
}

These keys have now been migrated to the following values:

  • negative500 -> negative400
  • negative600 -> negative500
  • positive500 -> positive400
  • positive600 -> positive500

iOS color palette changes

V2 theme default colorPalette values and the JSON keys used for positive and negative semantic colors have changed. If you customize the V2 theme, update your palette to match About Colors in the iOS Customization Guide v2.

ID Capture V2 - Error Screen Customization for Android

Wrong document side customization

If you previously customized the Wrong document side error screen, add the following new string resources:

<string name="onboard_sdk_id_capture_error_side_front">Capture the front side of the ID</string>
<string name="onboard_sdk_id_capture_error_side_back">Capture the back side of the ID</string>

This previous string is longer used:

<string name="onboard_sdk_id_capture_error_side">You’ve scanned the wrong document side. Please scan your document again.</string>

No internet connection customization

If you previously customized the No internet connection error screen, add the following new string resource:

<string name="onboard_sdk_no_internet_title">No internet connection</string>

This previously used string is still in use for other error screens and should be kept in your resources:

<string name="onboard_sdk_id_capture_error_title">There was a problem</string>

Retry button customization

The retry button is now customized using a different string resource:

<string name="onboard_sdk_id_capture_retry">Refresh</string>

This previously used string is still in use for other error screens and should be kept in your resources:

<string name="onboard_sdk_no_network_snackbar_action_text">Retry</string>

Selfie V2 - Error Screen Customization for Android

No internet connection customization

If you previously customized the No internet connection error screen, add the following new string resource:

<string name="onboard_sdk_no_internet_title">No internet connection</string>

This previously used string is still in use for other error screens and should be kept in your resources:

<string name="onboard_sdk_face_scan_failed_feedback_selfie_capture_failed_title">There was a problem</string>

Changes in behavior for device environment detection for Android

The behavior when detecting device environment vulnerabilities has changed:

  • Hook or virtual environment detection: Detecting hook or virtual environment vulnerabilities in the SDK triggers a native crash, which cannot be caught or handled by application code, resulting in immediate app termination.
  • Emulator and root detection: The flow is not aborted when emulator and root checks are detected. The onboarding process continues normally.

API Changes

The following initializeSDK() method optional parameters have been removed:

  • disableVirtualEnvironmentDetection
  • disableRootDetection
  • disableEmulatorDetection
  • disableHookCheck

If you were using these parameters in your code, remove them from your initializeSDK() method call. Device environment checks can no longer be disabled.

Added ability to pass SessionConfig to startFaceLogin() method for Android

Now you can supply an optional sessionConfig parameter to the startFaceLogin(), like this:

  let sessionConfig = {}; // Optional

  cordova.exec(
    function (result) {
      console.log("Face login Success: " + result);
    },
    function (error) {
      console.log("Face login Error: " + error);
    }, 
    "Cplugin", 
    "startFaceLogin",
    [sessionConfig]
  );

This allows enabling of end-to-end encryption (E2EE) in Face Login mode on Android.

Added ability to pass showIdTypeChooser parameter to the addId module

Now you can supply an optional showIdTypeChooser parameter to the addId module. It will be used by the SDK to decide whether to show the document type chooser. By default, if not supplied, showIdTypeChooser param is true.

{
  module: "addId", 
  idType: "passport", 
  showIdTypeChooser: "false"
}

setupOnboardingSession now accepts a session config object

The setupOnboardingSession method now expects a JSON object as the first argument instead of a plain string configurationId.

If you previously passed configurationId as a string, the method will silently fall back to an empty session configuration, which may cause unexpected behavior.

Before:

cordova.exec(resolve, reject, "Cplugin", "setupOnboardingSession", ["your-config-id"]);

After:

var sessionConfig = {
  configurationId: "your-config-id",
  // other optional fields:
  // token: "...",
  // e2eEncryptionEnabled: true,
  // mergeSessionRecordings: false,
  // validationModules: [...],
  // externalId: "...",
  // externalCustomerId: "...",
  // interviewId: "...",
};
cordova.exec(resolve, reject, "Cplugin", "setupOnboardingSession", [sessionConfig]);

Migration: Wrap your configurationId and any other session parameters in a JSON object and pass that object as the first element of the arguments array.

The same applies to startWorkflow and startFlow, which also accept a session config object as the first argument.

Updated startOnboardingSection method with additional parameters

You now have to provide recordSessionConfig and sectionTag parameters when calling startOnboardingSection to set the session recording configuration and section tagging.

Expected crashes when running in a virtual environment on Android

It is expected that the app crashes with the following stacktraces when a virtual environment is used. For example:

java.lang.NullPointerException
    at com.incode.welcome_sdk.ThemeConfiguration$Builder.setLabelSmallStyle(SourceFile:1066)
    at com.incode.welcome_sdk.f.c(SourceFile:150)
    at com.incode.welcome_sdk.data.local.m.as(SourceFile:22)
    at com.incode.welcome_sdk.IncodeWelcome.startOnboardingSection(SourceFile:18)
java.lang.NullPointerException: Attempt to get length of null array
    at com.incode.welcome_sdk.data.IncodeWelcomeRepository.d(SourceFile:320)
    at com.incode.welcome_sdk.data.IncodeWelcomeRepository.i(SourceFile:214)

Selfie V2: No Internet Error Screen Retry Button Change on Android

The retry button label shown on the Selfie Scan "No internet" error screen now uses a dedicated string resource:

<string name="onboard_sdk_face_scan_retry">Refresh</string>

The previous string was:

<string name="onboard_sdk_try_again">Try again</string>

If you overrode onboard_sdk_try_again to customize the retry button on the no internet screen, you must now override onboard_sdk_face_scan_retry instead. The onboard_sdk_try_again string is still used for other retry scenarios.

Selfie V2 - Capture-Only Mode Success Screen Text Change on Android

In capture-only mode, the Selfie Scan success screen now uses a different string resource:

<string name="onboard_sdk_face_captured">Face captured!</string>

This previously used string is still in use for non-capture-only mode and should be kept in your resources:

<string name="onboard_sdk_enroll_success">Success!</string>

ID Capture and Selfie V2: Permission Open Settings Screen Text Change on Android

The Open settings label shown on the Permission open settings screen now uses a dedicated string resource:

<string name="onboard_sdk_permission_allow_permission_action">Allow permission</string>

This previously used string is still in use for the Geolocation module and should be kept in your resources:

<string name="onboard_sdk_permission_open_setting_action">Open settings</string>

String Customization on iOS

Removed localization key incdOnboarding.curp.add.generate.

Renamed localization keys:

  • incdOnboarding.curp.generation.last.name.placeholder -> incdOnboarding.curp.generation.first.last.name.placeholder
  • incdOnboarding.curp.generation.name.placeholder -> incdOnboarding.curp.generation.first.name.placeholder

Migration to 4.1.0

Upload error screen customization on Android:

If you previously customized the upload error screen, add the following new string resource:

Add this string: <string name="onboard_sdk_validation_error_button_text">Scan your ID</string>

Previous string: <string name="onboard_sdk_id_capture_tutorial_title">Scan your ID</string>

This string is now used only for customizing the ID Capture V2 tutorial screen title.

Changed default values in FaceMatch module config on Android (optional)

With the move to UxV2, the showUserExists config is now false by default.

Migrate any custom ThemeConfiguration to the V2 equivalent on Android

If your previous integration had any UI customization in supported modules through Theme Configuration, these customizations will now need to be migrated to the equivalents in UXv2. See the Migrating Theme Configurations to UXv2 Guide for more details.

Migration to 4.0.0

Update string resources for the "Need Help" screen in the IdScan v2 module on Android

The "Need Help" screen has been redesigned on Android, and the customizable strings have been replaced. If you override any of the following strings in your app, replace them with the new ones listed below.

No action is required if you do not override these strings.

Replaced string resources

Replace overrides of:

<string name="onboard_sdk_id_capture_help_title">Need help?</string>
<string name="onboard_sdk_id_capture_help_subtitle">Some considerations</string>
<string name="onboard_sdk_id_capture_help_manual_photo_button_text">Take the photo manually</string>
<string name="onboard_sdk_id_capture_help_align_title">Center your document in the frame</string>
<string name="onboard_sdk_id_capture_help_align_subtitle">The photo will be taken automatically</string>
<string name="onboard_sdk_id_capture_help_blur_title">Avoid blurriness on the document</string>
<string name="onboard_sdk_id_capture_help_blur_subtitle">Zoom in and out, or tap on the document</string>
<string name="onboard_sdk_id_capture_help_glare_title">Avoid glare on the document</string>
<string name="onboard_sdk_id_capture_help_glare_subtitle">Find a better lighting to avoid reflections</string>
<string name="onboard_sdk_id_capture_help_darkness_title">Avoid darkness on the document</string>
<string name="onboard_sdk_id_capture_help_darkness_subtitle">Find a place with better lighting</string>

with:

<string name="onboard_sdk_id_capture_common_issues_title">Common issues</string>
<string name="onboard_sdk_id_capture_common_issues_glare_title">Glare present</string>
<string name="onboard_sdk_id_capture_common_issues_glare_subtitle">Tilt the ID slightly up or down to minimize the reflection</string>
<string name="onboard_sdk_id_capture_common_issues_blur_title">Blur present</string>
<string name="onboard_sdk_id_capture_common_issues_blur_subtitle">Move ID further away or closer to your phone until the image is focused</string>
<string name="onboard_sdk_id_capture_common_issues_info_not_readable_title">Info is not readable</string>
<string name="onboard_sdk_id_capture_common_issues_info_not_readable_subtitle">Minimize camera shake by holding your phone steady</string>
<string name="onboard_sdk_id_capture_common_issues_try_again_button">@string/onboard_sdk_try_again</string>

Upgrade compileSdk on Android

With the update of the internal CameraX dependencies, you will need to upgrade your project's compileSdk to level 35:

compileSdk 35

Update Gradle Wrapper on Android

Android Gradle Wrapper 8.6.0 requires Gradle 8.7 or higher. Update your Gradle wrapper configuration in gradle/wrapper/gradle-wrapper.properties:

distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip

If you use any of the following optional dependencies on Android, make sure to update to the latest versions

implementation 'com.incode.sdk:nfc:1.5.2'

Response Key Name Changes (Breaking Changes)

This version introduces breaking changes to ensure cross-platform consistency between Android and iOS response structures. The following response keys have been renamed:

Phone Number Module

Before:

{
  "phone": {
    "phone": "+1234567890"
  }
}

After:

{
  "phoneData": {
    "phone": "+1234567890"
  }
}

Migration: Update your code to use phoneData instead of phone when accessing phone number results.

  cordova.exec(function(winParam) {
-   const phoneNumber = winParam.phone.phone;
+   const phoneNumber = winParam.phoneData.phone;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addPhone"}]);

Signature Module

Before:

{
  "signaturePath": {
    "status": "success"
  }
}

After:

{
  "signatureData": {
    "status": "success"
  }
}

Migration: Update your code to use signatureData instead of signaturePath when accessing signature results.

  cordova.exec(function(winParam) {
-   const status = winParam.signaturePath.status;
+   const status = winParam.signatureData.status;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addSignature"}]);

Face Match Module - Existing User Field

Before:

{
  "faceMatchData": {
    "status": "match",
    "confidence": 1,
    "isExistingUser": true,
    "isFaceMatched": true,
    "isNameMatched": true
  }
}

After:

{
  "faceMatchData": {
    "status": "match",
    "confidence": 1,
    "existingUser": true,
    "isFaceMatched": true,
    "isNameMatched": true
  }
}

Migration: Update your code to use existingUser instead of isExistingUser when accessing face match results.

  cordova.exec(function(winParam) {
-   const isExisting = winParam.faceMatchData.isExistingUser;
+   const isExisting = winParam.faceMatchData.existingUser;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addFaceMatch"}]);

Geolocation Module

Before:

{
  "geodata": {
    "addressFields": {
      "city": "Belgrade",
      "colony": "Zvezdara",
      "postalCode": "",
      "street": "Banjska",
      "state": ""
    }
  }
}

After:

{
  "geoLocationData": {
    "addressFields": {
      "city": "Belgrade",
      "colony": "Zvezdara",
      "postalCode": "",
      "street": "Banjska",
      "state": ""
    }
  }
}

Migration: Update your code to use geoLocationData instead of geodata when accessing geolocation results.

  cordova.exec(function(winParam) {
-   const city = winParam.geodata.addressFields.city;
+   const city = winParam.geoLocationData.addressFields.city;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addGeolocation"}]);

Before:

// User consent result was previously returned inconsistently or not at all

After:

{
  "userConsentData": {
    "status": true
  }
}

Migration: If you're using the user consent module, the result is now consistently returned under the userConsentData key on both platforms.

  cordova.exec(function(winParam) {
    const consentGiven = winParam.userConsentData.status;
    // Process consent status
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [
    {"module":"addUserConsent", "title":"Privacy Policy", "content":"..."}
  ]);

Why These Changes?

These changes ensure that the JavaScript layer receives identical response structures from both Android and iOS platforms, making it easier to write cross-platform code without platform-specific conditionals.

Document Validation Module - documentData Structure

After (Version 4.0.0):

{
  "documentData": {
    "type": "addressStatement",     
    "image": "<base64String>",      
    "address": {                    
      "city": "",
      "colony": "",
      "postalCode": "",
      "street": "",
      "state": ""
    },
    "data": "<rawData>"            
  }
}

Migration: The structure is now standardized with clear field names. The type field indicates the document type (e.g., "addressStatement", "medicalDoc", "paymentProof"), image contains the base64-encoded image, and address contains structured address information when available.

ID Scan Module - frontIdData and backIdData Structure

Before:

{
  "frontIdData": {
    "scanStatus": "success",
    "idImageBase64": "<base64String>",
    // ... other Gson-serialized fields
  }
}

After (Version 4.0.0):

{
  "frontIdData": {
    "status": "ok",                   // Renamed from 'scanStatus'. On success: "ok", on error: "unknown", "errorClassification", "errorGlare", "errorSharpness", "errorReadability", "errorInCapture" (iOS only), "errorUnacceptableID" (iOS only), "wrongSide" (iOS only)
    "image": "<base64String>",        // Renamed from 'idImageBase64'
    "classifiedIdType": "ID",         // Classified document type
    "idCategory": "primary",          // 'primary' or 'secondary'
    "chosenIdType": "id"             // Chosen ID type: 'id' or 'passport'
  }
}

Migration: Update your code to use the new field names:

  cordova.exec(function(winParam) {
-   const scanStatus = winParam.frontIdData.scanStatus;
+   const scanStatus = winParam.frontIdData.status;
-   const idImage = winParam.frontIdData.idImageBase64;
+   const idImage = winParam.frontIdData.image;
+   const idCategory = winParam.frontIdData.idCategory;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addFrontId"}]);

Note: The same structure applies to backIdData.

ID Process Module - processIdData Structure

After (Version 4.0.0):

{
  "processIdData": {
    "extendedOcrData": "<jsonString>",  // Extended OCR data as JSON string
    "data": {                            // Structured OCR data
      "address": {                       // Address fields
        "city": "",
        "colony": "",
        "postalCode": "",
        "street": "",
        "state": ""
      },
      "fullAddress": "",                 // Complete address string
      "birthDate": 0,                    // Timestamp in milliseconds
      "expirationDate": 0,               // Unix timestamp
      "gender": "",
      "name": "",                        // Full name
      "issueDate": 0,                    // Unix timestamp
      "numeroEmisionCredencial": ""      // Credential emission number
    }
  }
}

Migration: The OCR data is now structured with clear field names and types. Date fields are provided as timestamps for easier manipulation. Access the structured data through the data field:

cordova.exec(function(winParam) {
  const ocrData = winParam.processIdData.data;
  const fullName = ocrData.name;
  const birthDate = new Date(ocrData.birthDate);
  const address = ocrData.address.city;
}, function(err) {
  console.log("Error: "+ err);
}, "Cplugin", "startOnboardingSection", [{"module":"processId"}]);

Selfie Scan Module - selfieData Structure

After (Version 4.0.0):

{
  "selfieData": {
    "status": "success",           
    "image": "<base64String>",     
    "spoofAttempt": false         
  }
}

Migration: The structure now includes explicit status and spoof detection fields for better fraud prevention handling.

Government Validation Module - govresult Structure

Before:

{
  "govresult": true  
}

After (Version 4.0.0):

{
  "govresult": {
    "status": true  
  }
}

Migration: Update your code to access the status field within the govresult object:

  cordova.exec(function(winParam) {
-   const isValidated = winParam.govresult;
+   const isValidated = winParam.govresult.status;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"governmentValidation"}]);

Approve Module - approveData Structure

After (Version 4.0.0):

{
  "approveData": {
    "status": "approved",           
    "id": "<uuid>",                 
    "customerToken": "<token>"     
  }
}

Migration: The approve result is now structured with clear field names. Previously all fields from the ApproveResult object were serialized via Gson. Now only the essential fields are exposed with consistent naming.

cordova.exec(function(winParam) {
  const approvalStatus = winParam.approveData.status;
  const sessionId = winParam.approveData.id;
  const token = winParam.approveData.customerToken;
}, function(err) {
  console.log("Error: "+ err);
}, "Cplugin", "startOnboardingSection", [{"module":"approve"}]);

NFC Scan Module - nfcData Structure

After (Version 4.0.0):

{
  "nfcData": {
    "birthDate": "",                        
    "compositeCheckDigit": "",              
    "dateOfBirthCheckDigit": "",            
    "documentCode": "",                     
    "documentNumber": "",                  
    "documentNumberCheckDigit": "",          
    "expirationDateCheckDigit": "",         
    "expireAt": "",                         
    "gender": "",                           
    "issuingStateOrOrganization": "",       
    "nationality": "",                      
    "optionalData1": "",                    
    "optionalData2": "",                    
    "personalNumber": "",                   
    "personalNumberCheckDigit": "",         
    "primaryIdentifier": "",                
    "secondaryIdentifier": "",              
    "status": true                          
  }
}

Migration: The NFC data structure provides comprehensive passport/ID chip information read from NFC-enabled documents. All fields are extracted from the MRZ (Machine Readable Zone) and chip data.

Migration to 3.0.0

  • It is mandatory that all sample apps now have to provide a source from where to fetch Incode's Android dependency from. For suggested method please check out the README.md page and its Additional Steps for Android section.

Migration to 2.9.0

Optional dependencies

For Android, if you use any of the following optional dependencies, make sure to update to the latest versions

implementation 'com.incode.sdk:video-streaming:1.6.0'
implementation 'com.incode.sdk:extensions:1.2.1'
implementation 'com.incode.sdk:model-face-recognition:3.5.1'
implementation 'com.incode.sdk:model-id-face-detection:3.5.1'
implementation 'com.incode.sdk:model-liveness-detection:3.2.1'

Android minSdk changes

For Android, if you use the video-streaming dependency, you need to upgrade your minSdk to 24 or higher. The requirement is coming from the OpenTok dependency, which now requires a minimum SDK version of 24. This update is necessary to ensure compatibility with the 16KB page size support mandated by Google starting from November 1st 2025. More info (https://developer.android.com/guide/practices/page-sizes).

Migration to 2.7.0

For Android, if you use any of the following optional dependencies, make sure to update to the latest versions

implementation 'com.incode.sdk:model-face-recognition:3.5.0'
implementation 'com.incode.sdk:model-id-face-detection:3.5.0'

The qr-face-login dependency is no longer available and has been removed in this version of the SDK. Please update your project configuration accordingly. Remove the qr-face-login dependency from your build.gradle:

  • Update Android minSdkVersion in you Android projects's build.gradle:
  buildscript {
    ext {
-    minSdkVersion = 21
+    minSdkVersion = 23
    }
  }

Remove com.incode.sdk:camera:1.1.0 dependency in your app’s build.gradle file:

  dependencies {
-    implementation 'com.incode.sdk:camera:1.1.0'
  }

Migration to 2.5.0

  • Update Android to compileSdk=34. It can be done by updating cordova-android package in package.json:
+ "cordova-android": "^13.0.0",
  • Update iOS deployment target to minimum version 13.0 and swift version to 5.0. Update config.xml:
+ <platform name="ios">
+    <preference name="SwiftVersion" value="5.0" />
+    <preference name="deployment-target" value="13.0" />
+ </platform>