Skip to content

Human Scoring

Read whether the current session comes from a real person at the moment your app makes a decision. The SDK keeps the classification up to date as the user interacts, so reading it is instant: it does not wait for the network and is safe to call on the main thread.

Note: Before you block users on getClassification(), read Going to production for the state of the model in the current release. How scoring works explains actions, evidence and thresholds.

In this use case

Page What it covers
Human Scoring (this page) Read the classification at a decision point
User Consent Ask the user for permission before anything is recorded
Sensitive Screens Pause capture while a password or payment field is on screen
Custom Events Mark moments in your app on the session timeline
Sessions Start a new session on logout or account switch

When to use it

  • Before creating an account, submitting a form, or redeeming a promotion
  • Before a step that bots abuse: posting, voting, adding to cart, claiming a reward
  • To decide which branch of your own flow to take — let the user through, or add a challenge

Prerequisites

  • The SDK is installed and initialized. See the Quick Start.
  • The user has consented. Without consent nothing is recorded and the answer stays INSUFFICIENT. See User Consent.
  • The user has interacted with the app. Until the session has as many actions as the model asks for — 8 with the built-in model — it is not sufficient and the answer is INSUFFICIENT. Right after launch there are none. See Evidence.

Usage

Read the classification

import ai.dea.sdk.ClassificationResult
import ai.dea.sdk.DeaSdk

when (DeaSdk.instance?.getClassification()?.result) {
    ClassificationResult.HUMAN -> {
        // A person. Allow the action.
    }
    ClassificationResult.BOT -> {
        // A bot, by the SDK's reading.
    }
    ClassificationResult.UNDETERMINED -> {
        // Between the thresholds. Take your fallback path.
    }
    ClassificationResult.INSUFFICIENT, null -> {
        // Too early to tell, or no SDK. Not a bot: take your fallback path.
    }
}

getClassification() returns one of four answers:

result When
INSUFFICIENT Not enough evidence yet, or an SDK that cannot score. value is null
HUMAN The score is at or above the model's humanThreshold
BOT The score is below the model's botThreshold
UNDETERMINED A score between the two thresholds

A model that sets no humanThreshold has one bar: a score at or above botThreshold is HUMAN.

What each answer allows is your decision. An answer between the thresholds is not counted as a person: where only a person may pass, UNDETERMINED does not pass, so give it a fallback such as a challenge. The read includes the user's most recent touch.

Tell "not enough evidence yet" apart from the other answers

import ai.dea.sdk.ClassificationResult
import ai.dea.sdk.DeaSdk

val answer = DeaSdk.instance?.getClassification() ?: return

if (answer.result == ClassificationResult.INSUFFICIENT) {
    // Too early to tell. Let the user keep going, or ask them to interact a little more.
    showHint("Keep going")
}

getClassification() returns a Classification:

Field Type Description
result ClassificationResult HUMAN, BOT, UNDETERMINED or INSUFFICIENT
value Double? The session's score, 0 to 1; null exactly when result is INSUFFICIENT
actions Int The scored actions behind value; the result leaves INSUFFICIENT once there are as many as the loaded model asks for, 8 for the built-in model
botThreshold Double? The loaded model's bot threshold
humanThreshold Double? The loaded model's human threshold; null when the model sets none
modelVersion Int? The model the thresholds come from; 0 for the built-in one

The thresholds come from the loaded model only. Every field comes from one reading, so they always agree with each other. When the SDK downloads a newer model during a session, the next reading comes from it, and modelVersion changes.

Handle a model without thresholds

getClassification() throws ThresholdMissing when the loaded model sets no bot threshold — a model file from before thresholds were part of the model. The SDK has no other threshold to fall back on, so catch it and take your undetermined path.

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

val result = try {
    DeaSdk.instance?.getClassification()?.result
} catch (missing: ThresholdMissing) {
    Log.w("MyApp", "model ${missing.modelVersion} has no thresholds")
    ClassificationResult.UNDETERMINED
}

Check that the SDK can score

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

val dea = DeaSdk.instance

if (dea == null) {
    // DeaSdk.init has not been called.
} else if (!dea.ready) {
    Log.w("MyApp", "DEA cannot score: ${dea.coreFault}")
}

When ready is false, the SDK still runs but cannot score: getClassification() answers INSUFFICIENT with a null value, and coreFault says why.

Examples

Gate a sign-up button

import ai.dea.sdk.ClassificationResult
import ai.dea.sdk.DeaSdk
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity

class SignUpActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sign_up)

        findViewById<Button>(R.id.create_account).setOnClickListener {
            if (DeaSdk.instance?.getClassification()?.result == ClassificationResult.HUMAN) {
                signUp()
            } else {
                showChallenge() // e.g. show a captcha
            }
        }
    }

    private fun signUp() { /* … */ }

    private fun showChallenge() { /* … */ }
}

API

Member Returns Description
getClassification() Classification HUMAN, BOT, UNDETERMINED or INSUFFICIENT, with the score and thresholds behind it. Throws ThresholdMissing for a model without thresholds
ready Boolean Whether the SDK is able to score
coreFault String? Why the SDK cannot score, if it cannot