API Reference¶
Start the SDK with DeaSdk.init(context, config), then reach it anywhere with DeaSdk.instance.
Types that come from the companion library (Consent, SessionInfo, CaptureEvent, …) are in
the ai.dea.base package; attestation types are in ai.dea.sdk.attest, proof types in
ai.dea.sdk.proof, and model types in ai.dea.sdk.model.
DeaSdk¶
init¶
fun init(
context: Context,
config: DeaConfig = DeaConfig(),
targets: TargetReader = ViewTargetReader(),
): DeaSdk
Starts the SDK and capture. Returns the running instance if one exists. Never throws. Call it on
the main thread, and pass your Application: the SDK keeps the Context it is given. See
Options.
instance¶
The running instance, or null before init and after dispose().
ready¶
Whether the SDK is able to score. When false, capture continues, getClassification() answers
INSUFFICIENT, and coreFault says why.
coreFault¶
Why the SDK cannot score, or null.
getClassification¶
Whether the session reads as a person, a bot, or neither yet, with the score and the model's thresholds behind the answer. One snapshot: it covers every interaction so far, and its fields always agree with each other. Synchronous; safe on the main thread. See Human Scoring.
Throws: ThresholdMissing when the loaded model sets no bot threshold. When the SDK cannot
score (ready is false) it does not throw; it answers INSUFFICIENT with a null value.
consent¶
The user's current consent answer. See User Consent.
setConsent¶
| Parameter | Type | Description |
|---|---|---|
granted |
Boolean |
Whether the user agreed |
remember |
Boolean |
false keeps the answer for this launch only and stores nothing |
Takes effect immediately. Withdrawing discards anything captured but not yet processed. The session is kept either way.
pause¶
Stops recording. The session is kept. See Sensitive Screens.
resume¶
Starts recording again after pause(). Does not override consent.
captureEvent¶
| Parameter | Type | Description |
|---|---|---|
name |
String |
1 to 64 characters; otherwise the event is dropped |
data |
Map<String, Any?>? |
Optional; at most 1024 bytes as JSON, or the event is dropped |
Returns: Boolean — true when the event was recorded.
See Custom Events.
captureKey¶
fun captureKey(
keyClass: KeyClass,
pressed: Boolean = true,
mods: Int = 0,
repeat: Boolean = false,
field: String? = null,
)
| Parameter | Type | Description |
|---|---|---|
keyClass |
KeyClass |
Which kind of key: KeyClass.of(character) turns a typed character into one |
pressed |
Boolean |
false reports a release. A soft keyboard has none to report; send the press alone |
mods |
Int |
Modifier keys held, as KeyMod bits; 0 on a soft keyboard |
repeat |
Boolean |
Whether the press is a key repeat |
field |
String? |
The name of the text field typed into, as for a view's target name |
Reports one key press that your app saw. The SDK sees no key events of its own, so key presses are
recorded only when your app reports them, and only their class — never the character. Records
nothing unless events includes CaptureEvent.KEY_DOWN (and
CaptureEvent.KEY_UP for releases), and nothing while capture is paused or before consent. Never
call it for a password field.
setMotion¶
Switches the motion sensors off, or back on, for the running app. While off, the SDK reads no
motion data and sessionInfo.device.sensorRate is 0; touch capture and the session continue.
motion says whether the sensors are on.
reset¶
Ends the current session and starts a new one. See Sessions.
sessionInfo¶
The current session id, device and SDK version.
modelInfo¶
Which model is scoring: its version (0 for the built-in model) and its source: EMBEDDED,
CACHE (downloaded at an earlier launch) or NETWORK (downloaded during this run). See
Model options.
checkForModel¶
Checks DEA's model host now, if a day has passed since the last check; force = true checks
anyway. The SDK already checks at every launch and on returning to the foreground, so most apps
never call this. Never throws. Blocking — call it off the main thread. Answers with
ModelCheckOutcome.CANCELLED when model updates are off.
addModelListener¶
Calls listener each time a newer model starts scoring during this run, on a background thread.
Returns the unsubscribe.
attest¶
Registers the device key with DEA and turns on automatic renewal. Cached until near expiry. Never
throws. Blocking — call it off the main thread. Answers UNSUPPORTED without a request when no
appKey was given. See Attest.
renewAttestation¶
Registers again now. A failure keeps the registration already held. Blocking.
lastAttestation¶
The last attestation result, or null before the first attest().
storedAttestation¶
The registration this install already holds, if it is still fresh, read from storage without a
request; null otherwise. A fresh one turns on automatic renewal.
forgetAttestation¶
Forgets the stored registration and any wait after refused attempts, and stops automatic renewal. The device key is kept.
nextAttestationRefresh¶
When the registration will next be renewed automatically, in epoch seconds.
onAttestationEvent¶
Called on every automatic renewal decision: Scheduled(afterSeconds), Fired(verdict) or Idle.
Set it before the first attest().
Ads¶
Android has no ad session object. These three calls each sign one ad event — the session's current
score, signed with the device key — and send it or return it. For DEA to accept a proof, pass
appKey, set
registryAppId to your appId, and register the device
key with attest(). See Ads.
sendProof¶
fun sendProof(
event: ProofEvent,
sessionId: String? = null,
attestation: Attestation? = null,
adUnit: String? = null,
appScopedUid: String? = null,
extra: Map<String, Any?> = emptyMap(),
update: Boolean = false,
): RecordOutcome
| Parameter | Type | Description |
|---|---|---|
event |
ProofEvent |
The ad event |
sessionId |
String? |
The ad session's id, signed into the proof. "" for an impression, so DEA opens the session and answers with its id; that id for the click and the end. null signs the capture session's id (sessionInfo.session), which is not an ad session's id |
attestation |
Attestation? |
Sets the tier claim only: B for a PASSED registration that carried a Play Integrity token and has not expired, C otherwise. null takes the registration the SDK holds from attest() |
adUnit |
String? |
The ad unit, signed into the proof. Pass the same one for an ad's three events |
appScopedUid |
String? |
Signed into the proof as app_scoped_uid; left out when null |
extra |
Map<String, Any?> |
Unsigned fields sent in the request body beside the proof. They never replace the proof or the SDK version |
update |
Boolean |
true sends the proof as an update of the ad session sessionId names, PUT /api/sessions/{sessionId}, rather than POST /api/sessions. Use it for AD_ENDED |
Fetches a challenge from DEA, signs the event, and sends the proof. The proof carries the score
the scoring engine holds, when its evidence ends, how many interactions are behind it, and the
model version; your app cannot set those. Its appId is registryAppId, or the app id DEA's
challenge names when it names one. If the challenge fails, the proof is signed and sent without
DEA's nonce.
When DEA cannot be reached or answers 5xx, the proof is sent again after 2 seconds, doubling to
30, plus up to 1 second: at most five sends in all, and none after the proof expires 90 seconds
after signing. A 4xx is final. Blocking through the retries — call it off the main thread.
Refused without a request when no appKey was given. Signs nothing when the device has no key, when
the scoring engine is not running, or when the session is not sufficient yet
(getClassification().result is INSUFFICIENT): an impression declared then is not recorded. The
click is not checked against the user's touches.
Returns: RecordOutcome — whether DEA accepted the proof, the proof, and what DEA or the SDK
said. See Ads: Find out why a proof was not accepted.
record¶
fun record(
event: ProofEvent,
sessionId: String? = null,
attestation: Attestation? = null,
adUnit: String? = null,
appScopedUid: String? = null,
extra: Map<String, Any?> = emptyMap(),
update: Boolean = false,
): Boolean
The same send as sendProof, with the same parameters. Blocking.
Returns: Boolean — true when DEA accepted the proof. To read DEA's session id after an
impression, use sendProof.
getProof¶
fun getProof(
event: ProofEvent,
sessionId: String? = null,
attestation: Attestation? = null,
adUnit: String? = null,
appScopedUid: String? = null,
): SignedProof?
Signs one event as sendProof does, and returns the proof without sending it, for an app that
delivers proofs itself. The parameters are sendProof's. Blocking: it fetches the challenge.
Not refused without appKey.
Returns: SignedProof? — the proof, or null when nothing was signed: no device key, the
scoring engine is not running, or not enough evidence yet. No reason is given; sendProof's
said gives it.
dispose¶
Stops capture, drops anything not yet processed, and releases the SDK.
DeaConsentDialog¶
show¶
fun show(
activity: Activity,
sdk: DeaSdk? = DeaSdk.instance,
copy: ConsentCopy = ConsentCopy(),
remember: Boolean = true,
ask: Boolean = true,
onResult: (Boolean) -> Unit = {},
)
| Parameter | Type | Description |
|---|---|---|
activity |
Activity |
A showing activity to attach the dialog to |
sdk |
DeaSdk? |
The SDK to record the answer on |
copy |
ConsentCopy |
The dialog's text |
remember |
Boolean |
false clears the stored answer, asks on every call, and keeps each answer for this launch only |
ask |
Boolean |
false reads the stored answer without showing anything |
onResult |
(Boolean) -> Unit |
Called on the main thread with the answer |
Shows the consent dialog unless an answer is stored, and records the answer. Call it on the main thread. See User Consent.
Functions¶
View.deaTarget¶
Declares what a view is: its name, and which kind of control it is. Overrides what the SDK would
infer. See Options: targets.
Types¶
DeaConfig¶
See Options. The proofs of the Ads calls also read
registryAppId: the appId signed inside each proof.
Set it to your appId; left null, proofs carry a development id that DEA refuses.
Classification¶
| Field | Type | Description |
|---|---|---|
result |
ClassificationResult |
The answer |
value |
Double? |
The session's score, 0 to 1; null exactly when result is INSUFFICIENT |
actions |
Int |
Interactions behind value; the result stays INSUFFICIENT until there are as many as the loaded model asks for, 8 for the built-in model |
botThreshold |
Double? |
Below this, a sufficient session is a bot. The loaded model's; null when the SDK cannot score |
humanThreshold |
Double? |
At or above this, a sufficient session is a person. The loaded model's; null when the model sets none |
modelVersion |
Int? |
The model the thresholds come from, 0 for the built-in one; null when the SDK cannot score |
The thresholds come from the loaded model only. No account setting and no built-in constant changes them.
ClassificationResult¶
Checked in this order:
| Value | When |
|---|---|
INSUFFICIENT |
No scoring engine, or fewer actions than the loaded model asks for. value is null |
HUMAN |
value at or above humanThreshold |
BOT |
value below botThreshold |
HUMAN |
No humanThreshold, and value at or above botThreshold |
UNDETERMINED |
value between the two thresholds |
Migrating to this release:
Classification.sufficientis gone, andClassificationResulthas a fourth value.
Before This release c.sufficient == falsec.result == ClassificationResult.INSUFFICIENTc.valuewhile not sufficient: a numbernullClassificationResulthas three valuesFour: handle INSUFFICIENTin every exhaustivewhenNo humanThreshold,valueat or abovebotThreshold:UNDETERMINEDHUMAN
ThresholdMissing¶
Thrown by getClassification() when the loaded model sets no bot threshold — a model file older
than thresholds. modelVersion names it. There is no fallback threshold: catch it and treat the
session as undetermined.
Consent¶
| Member | Type | Description |
|---|---|---|
decision |
ConsentDecision |
UNKNOWN, GRANTED or DENIED |
isAnswered |
Boolean |
Whether the user has answered |
isGranted |
Boolean |
Whether the user agreed |
forget() |
Unit |
Clears the stored answer so the user is asked again |
onChange(listener) |
() -> Unit |
Calls listener with the new decision when it changes; returns the unsubscribe |
Consent() |
constructor | An answer kept for this launch only |
Consent(store) |
constructor | An answer kept in your own ConsentStore |
Consent.granted() |
Consent |
An answer that is already yes |
ConsentStore¶
Where a Consent keeps its answer. write(ConsentDecision.UNKNOWN) means the answer was
forgotten.
ConsentCopy¶
The consent dialog's text: title, body, recorded, notRecorded, recordedLabel,
notRecordedLabel, closing, accept, decline. Every field has an English default. See
User Consent.
CaptureEvent¶
POINTER, SCROLL, MOTION, LIFECYCLE, CUSTOM, KEY_DOWN, KEY_UP. The default,
CAPTURE_EVENTS, is the first five. See Options: events.
KeyClass¶
LETTER, DIGIT, SPACE, DELETE, NAVIGATION, MODIFIER, OTHER (punctuation, Enter and
anything else). KeyClass.of(char: String) classifies a typed character as LETTER, DIGIT,
SPACE or OTHER.
TargetBucket¶
UNKNOWN, BUTTON, LINK, INPUT, SCROLLER, CANVAS, BACKGROUND.
SessionInfo¶
| Field | Type | Description |
|---|---|---|
session |
String |
Current session id, a UUID |
device |
DeviceRecord |
Current device information |
sdk.version |
String |
SDK version |
sdk.core |
String |
Which scoring engine build is running; none when the SDK cannot score |
startedAt |
Long |
When the session started, Unix milliseconds |
DeviceRecord¶
| Field | Type | Description |
|---|---|---|
surface |
Surface |
Screen size in dp (width, height) |
pixelRatio |
Double |
Physical pixels per dp |
rotation |
Int |
Screen rotation: 0, 90, 180 or 270 |
maxTouchPoints |
Int |
How many touches the screen declares it can follow at once |
sensorRate |
Int |
The requested motion rate, in Hz, once motion data has arrived; 0 before that and while motion is off |
os |
Int |
Operating system code |
runtime |
Int |
SDK runtime code |
ModelInfo¶
| Field | Type | Description |
|---|---|---|
version |
Int |
The model's version; 0 for the built-in model |
source |
ModelSource |
EMBEDDED, CACHE or NETWORK |
ModelCheck¶
| Field | Type | Description |
|---|---|---|
outcome |
ModelCheckOutcome |
NOT_DUE, UNCHANGED, NOT_PUBLISHED, NOT_SUPPORTED, LOADED, REFUSED, FAILED or CANCELLED |
detail |
String? |
What went wrong, when something did |
Attestation¶
| Field | Type | Description |
|---|---|---|
supported |
Boolean |
Whether the SDK could register: false when no key could be created, or no appKey was given |
verdict |
Verdict |
PASSED, FAILED or UNSUPPORTED |
platformAttested |
Boolean |
Whether a Play Integrity token went with an accepted registration |
platformTokenSpent |
Boolean |
Whether this attempt obtained a Play Integrity token, whatever DEA answered |
integrity |
String? |
DEA's reading of the device's integrity, when DEA returned one |
expiresAt |
Long? |
Expiry, epoch seconds |
kid |
String? |
Key identifier |
tier |
String? |
Trust tier assigned by DEA |
backing |
String? |
Where the key is kept: strongbox, tee or software |
detail |
String? |
Why the SDK did not register, or what DEA or the network answered when it failed |
ProofEvent¶
| Value | wire |
The event |
|---|---|---|
AD_IMPRESSION |
ad.impression |
The ad is on screen |
AD_CLICK |
ad.click |
The ad was clicked |
AD_ENDED |
ad.ended |
The ad is gone |
wire is the event_type signed into the proof. There are no other values.
RecordOutcome¶
| Field | Type | Description |
|---|---|---|
accepted |
Boolean |
Whether DEA accepted the proof |
signed |
SignedProof? |
The proof that was signed, or null when nothing was |
isSigned |
Boolean |
Whether signed is not null |
said |
String? |
DEA's answer as it came, or why DEA was never reached or did not accept |
sessionId |
String? |
The session_id in DEA's answer, or null when it named none. After an impression, the ad session's id: pass it to the click and the end |
SignedProof¶
| Member | Type | Description |
|---|---|---|
proof |
String |
The compact JWS, header.payload.signature, signed with the device key (ES256) |
score |
Double |
The score signed into the proof, 0 to 1 |
evidenceAt |
Long |
When the evidence behind score ends, epoch seconds |
windows |
Int |
How many scored interactions are behind score |
sessionId |
String |
The session_id signed into the proof |
event |
ProofEvent |
The event signed into the proof |
modelVersion |
Int? |
The version of the model that produced score, 0 for the built-in one; null when the proof carries none |
composedBy |
ProofSource |
Who composed what was signed: CORE, the scoring engine, for every proof DeaSdk signs |
composedBytes |
Int? |
How many bytes were signed |
header |
JSONObject? |
The signed header, decoded: alg, typ, kid |
claims |
JSONObject? |
The signed claims, decoded |
signature |
String? |
The signature segment, base64url |
score, evidenceAt, windows and modelVersion are read back out of the signed claims.