Skip to content

Troubleshooting

getClassification() always returns INSUFFICIENT or UNDETERMINED

Cause: One of the following:

  1. The user has not consented, or declined, so nothing is recorded.
  2. The session has fewer actions than the model asks for, 8 with the built-in model: the result is INSUFFICIENT. See Evidence.
  3. Capture was paused and never resumed.
  4. The SDK cannot score: ready is false and the result is INSUFFICIENT.
  5. The result is UNDETERMINED: the score lies between botThreshold and humanThreshold.

Solution: Check each in turn:

import ai.dea.sdk.DeaSdk
import android.util.Log

val dea = DeaSdk.instance!!

Log.d("MyApp", "consent: ${dea.consent.decision}") // must be GRANTED
Log.d("MyApp", "ready: ${dea.ready}")              // must be true
Log.d("MyApp", "fault: ${dea.coreFault}")          // must be null
Log.d("MyApp", "answer: ${dea.getClassification()}") // INSUFFICIENT means fewer actions than the model asks for

Make sure every pause() has a matching resume().

getClassification() throws ThresholdMissing

Cause: The model the SDK loaded sets no bot threshold. It is a model file from before thresholds were part of the model, and the SDK has no other threshold to fall back on.

Solution: Catch the exception and treat the session as undetermined. ThresholdMissing.modelVersion names the model that is loaded; send it to DEA support.

Nothing is logged after touching the screen with debug = true

Cause: Nothing is being recorded. Usually the user has not consented yet; otherwise capture is paused, events excludes the input you are testing, or the touch was inside a dialog or popup window, which the SDK does not capture.

Solution: Ask for consent — see User Consent. If consent is granted, check for a pause() without a matching resume(), and check events.

Debug lines are written to standard output. In Logcat they appear under the tag System.out, prefixed [dea]; make sure your Logcat filter does not hide that tag.

Touches on the first screen are not captured

Cause: DeaSdk.init was called from an activity that was already showing, with a Context other than that activity — for example applicationContext. The SDK finds the windows of activities started after init, and of the activity passed to init, but not of others already on screen.

Solution: Call DeaSdk.init in Application.onCreate(). If you must initialize from an activity, pass the activity itself.

ready is false and coreFault says there is no core in this build

Cause: The SDK's native library is missing from your APK for the device's ABI — usually because abiFilters, ABI splits or a packaging rule removed it.

Solution: Keep the ABIs your users' devices need, and do not exclude the SDK's .so files (libdea_jni.so and libdea_core.so):

// app/build.gradle.kts
android {
    defaultConfig {
        ndk {
            abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64")
        }
    }
}

The SDK ships arm64-v8a, armeabi-v7a, x86 and x86_64.

ready is false for another reason

Cause: The scoring engine packaged in your app is not the one the SDK expects. This should not happen with a published release. It can happen when another dependency brings its own copy of the SDK's native libraries and a packaging rule such as pickFirsts keeps that copy.

Solution: Make sure Gradle resolved ai.dea:dea-sdk and ai.dea:dea-base to the same version, and that no other dependency bundles libdea_core.so:

./gradlew :app:dependencies --configuration releaseRuntimeClasspath | grep ai.dea

If they match, send the coreFault text to DEA support.

A second DeaSdk.init call ignores its options

Cause: DeaSdk.init was called more than once. The first call's options stay in effect, and later calls return the running instance without a warning.

Solution: Call DeaSdk.init once, in Application.onCreate(). If you really need different options, call DeaSdk.instance?.dispose() first.

Cause: The answer is not being stored. The SDK was started with consent = Consent(), the answer was recorded with remember = false, or your app asks without checking consent.isAnswered first.

Solution: Leave the consent option at its default and remember at true unless the device is shared, and only ask when DeaSdk.instance?.consent?.isAnswered == false. DeaConsentDialog.show does that check for you.

attest() returns FAILED with NetworkOnMainThreadException in detail

Cause: attest() was called on the main thread. It makes network requests and blocks.

Solution: Call it from a background thread:

val attestation = withContext(Dispatchers.IO) { DeaSdk.instance?.attest() }

The same applies to renewAttestation().

attest() returns UNSUPPORTED

Cause: One of the following:

  1. No appKey was passed to DeaSdk.init. attestation.detail then says so, and no request was made.
  2. No signing key could be created: the device runs Android 5.x (API 21 or 22), which the SDK does not create keys on, or its keystore refused.

Solution: Pass the appKey DEA issued with your appId — see Options: appKey. Otherwise, test on a device running Android 6.0 or later.

attest() passes but platformAttested is false

Cause: No Play Integrity token went with the registration. This is expected on emulators without Google Play, on devices without Google Play services, and when Play refuses the request — most often because the build was not installed from Google Play or signed with a key registered in Play Console.

Solution: Test on a real device with a build distributed through Google Play — for example an internal testing track.

attest() returns FAILED and detail says attestation is paused

Cause: An earlier registration that used a Play Integrity token failed, and the SDK is waiting before it tries again: one hour after the first failure, doubling up to seven days. The wait survives app restarts.

Solution: Fix what made the earlier attempt fail, then call forgetAttestation() to end the wait, and attest() again.

attest() returns FAILED

Cause: DEA refused the registration, or could not be reached.

Solution: Read attestation.detail. It carries DEA's response, or the network error. Also check that playIntegrityProject is the project number DEA issued for your app.