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 |
Related¶
- User Consent — nothing is scored before consent
- API Reference