API Reference¶
DeaSdk¶
init¶
static DeaSdk init(
DeaOptions options, {
int? playIntegrityProject,
String? appKey,
String? registryAppId,
Directory? modelDirectory,
bool modelUpdates = true,
Duration modelTimeout = const Duration(seconds: 30),
})
Starts the SDK and capture. Returns the running instance if one exists. Never throws. See Options.
registryAppId is the appId written inside the proofs that the Ads calls sign; set it
to this platform's appId. See Options.
instance¶
The running instance, or null before init and after dispose().
error¶
Why the SDK cannot score, or null.
isScoring¶
Whether the SDK is able to score. When false, getClassification() answers insufficient with
a null value, and error says why.
getClassification¶
The one score read: the score, the evidence behind it and the loaded model's thresholds,
classified as human, bot, undetermined or insufficient in one snapshot. Synchronous, no network; includes
the latest gesture. The thresholds come from the loaded model only.
See Human Scoring.
Throws ThresholdMissing (with modelVersion) when the loaded model has no bot threshold. Never
throws when the SDK cannot score.
consent¶
The user's current consent answer. See User Consent.
setConsent¶
| Parameter | Type | Description |
|---|---|---|
granted |
bool |
Whether the user agreed |
remember |
bool |
Store the answer on the device. false keeps it for this run only |
Takes effect immediately. Withdrawing discards anything captured but not yet processed.
pause¶
Stops recording. The session is kept. See Sensitive Screens.
resume¶
Starts recording again after pause(). Does not override consent.
setMotion¶
Switches the motion sensors off (false) or back on (true) for this run. While off, no motion
data is recorded and getSessionInfo().device.sensorRate reads 0; touch capture and the session
continue. The classification then has less evidence to work with.
motion¶
Whether the motion sensors are on. true unless setMotion(false) was called.
captureEvent¶
| Parameter | Type | Description |
|---|---|---|
name |
String |
Up to 64 characters; longer names are shortened |
data |
Map<String, Object?>? |
Optional; at most 1024 bytes as JSON, or the event is dropped |
See Custom Events.
captureKey¶
void captureKey(
KeyClass keyClass, {
bool pressed = true,
int mods = 0,
bool repeat = false,
String? field,
})
Reports one keystroke your app saw. Does nothing unless EventKind.keyDown (for a press) or
EventKind.keyUp (for a release) is in events.
| Parameter | Type | Description |
|---|---|---|
keyClass |
KeyClass |
The kind of key — never the character. KeyClass.of(char) classes a character |
pressed |
bool |
false reports a release |
mods |
int |
Modifiers held, as KeyMod flags; 0 on a soft keyboard |
repeat |
bool |
Whether the press is a keyboard autorepeat |
field |
String? |
A stable name for the field; defaults to the focused widget's semantics identifier |
Never call it for a password field. See Report typing.
capturePointer¶
void capturePointer({
required EventKind kind,
required int pointerId,
required double x,
required double y,
required int atEpochMs,
Tool tool = Tool.touch,
Force? force,
Contact? contact,
Target? target,
})
Reports one pointer event from a surface Flutter does not route, such as a web view. Dropped while
paused, before consent, after dispose(), and when kind is not in
events.
| Parameter | Type | Description |
|---|---|---|
kind |
EventKind |
down, move, up, cancel, scroll or hover |
pointerId |
int |
Identifies one finger or pointer across its events |
x, y |
double |
Position in logical pixels, global to the app window |
atEpochMs |
int |
When the event happened, Unix milliseconds |
tool |
Tool |
What produced it; touch by default |
force |
Force? |
Pressure as value within the device's min..max, if known |
contact |
Contact? |
Contact size, if known |
target |
Target? |
What the touch landed on; read on down only |
See Report touches inside a web view.
reset¶
Ends the current session and starts a new one. See Sessions.
getSessionInfo¶
The current session id, device and SDK version.
attest¶
Registers the device key with DEA. A passed result is reused until near expiry. Never throws.
See Attest.
The first call also starts automatic renewal: the SDK registers the same key again one minute
before the registration expires, and checks again whenever the app returns to the foreground. A
renewal that fails is retried after 30 seconds, then 1, 2, 5 and 15 minutes, then every 15
minutes. The kid does not change. Your app does not need its own renewal timer.
attestation¶
The last attest() result in this run, including a refusal, or null before the first call.
storedAttestation¶
The registration kept on the device, if still fresh, read without any network request. null
when attest() would have to register again.
A registration found here also starts automatic renewal, as attest() does.
forgetAttestation¶
Forgets this install's registration, in memory and on the device, and stops automatic renewal. The
next attest() registers again, with the same device key and kid. For example, when a different
account signs in.
nextAttestationRefresh¶
When the next automatic renewal is due, in Unix seconds. null before the first attest(), and on
a device that cannot keep a key.
onAttestationEvent¶
Called for each renewal decision: RefreshScheduled(after), RefreshFired(verdict) or
RefreshIdle(). Set it before the first attest() to see the first schedule.
Model updates¶
Active only when modelDirectory is passed to init. See
Options.
model¶
The model in use: version (0 for the built-in model) and source (ModelSource.embedded,
cache or network).
modelChanges¶
Emits each time a newer model starts scoring during this run. Empty when updates are off.
checkForModel¶
Checks for a newer model now, if a day has passed since the last check. force: true
checks regardless; use it for a button a person presses, never on a schedule. Never throws.
The result's outcome is a ModelCheckOutcome, and its detail says more when there is more to
say:
| Outcome | Meaning |
|---|---|
notDue |
Less than a day since the last check; nothing was asked |
unchanged |
No newer model is published |
notPublished |
No model is published for this platform |
notSupported |
A newer model is published, but it needs a newer SDK release |
loaded |
A newer model was downloaded and is scoring now |
refused |
A model was downloaded, and the scoring engine refused it; the model in use is kept |
failed |
No usable answer: offline, a timeout, or a download that did not check out |
cancelled |
Model updates are not running (no modelDirectory, modelUpdates: false, or the SDK cannot score), or the SDK was disposed |
lastModelCheck¶
How and when the last check ended, or null before one has run.
Ads¶
Flutter has no ad session object and does not check that the user touched an ad. These three
calls sign a proof for one ad event with the device key; sendProof and record also send it to
DEA. See Ads.
Every call first asks DEA for a single-use nonce to sign in, and signs without one when DEA gives
none. The scoring engine composes the score claims, so nothing is signed while the classification is
insufficient. The calls do not check appKey or the attestation.
| Parameter | Type | Description |
|---|---|---|
sessionId |
String |
The ad's session id, signed as session_id. '' for adImpression, so that DEA makes the id; the id DEA answered for adClick and adEnded. Not the capture session id |
event |
ProofEvent |
The ad event, signed as event_type |
attestation |
Attestation? |
Decides the tier the proof claims: B when verdict is passed and platformAttested is true, C otherwise. Defaults to attestation, the last attest() result |
adUnit |
String? |
The ad unit the ad loaded into, signed as ad_unit. Left out when null |
appScopedUid |
String? |
A pseudonymous id for the user in your app, signed as app_scoped_uid. Left out when null |
extra |
Map<String, Object?> |
sendProof and record only. Unsigned fields added to the request body beside the proof. They never replace h_proof or sdk_version |
update |
bool |
sendProof and record only. true sends the proof as PUT /api/sessions/{sessionId} instead of POST /api/sessions. Pass it with adEnded |
sendProof¶
Future<RecordOutcome> sendProof({
required String sessionId,
required ProofEvent event,
Attestation? attestation,
String? adUnit,
String? appScopedUid,
Map<String, Object?> extra = const {},
bool update = false,
})
Signs one proof and sends it to DEA. The RecordOutcome says whether DEA accepted it, carries
the session id DEA answered with, and says why when it was not accepted.
When DEA cannot be reached or answers with a 5xx status, the same proof is sent again after 2,
4, 8 and 16 seconds, plus up to 1 second each, at most five sends in all, and never after the
proof expires, 90 seconds after signing. A 4xx answer is final. The future completes after the
last send. Nothing is kept on the device.
record¶
Future<bool> record({
required String sessionId,
required ProofEvent event,
Attestation? attestation,
String? adUnit,
String? appScopedUid,
Map<String, Object?> extra = const {},
bool update = false,
})
The same as sendProof, answering only whether DEA accepted the proof. It does not return the
session id DEA answers an impression with: send the impression with sendProof.
getProof¶
Future<SignedProof?> getProof({
required String sessionId,
required ProofEvent event,
Attestation? attestation,
String? adUnit,
String? appScopedUid,
})
Signs one proof without sending it. null when nothing was signed: no device key, no scoring
engine, the classification still insufficient, or the device key did not sign. The proof is valid for
90 seconds after signing.
dispose¶
Stops capture, drops anything not yet processed, and releases the SDK.
Functions¶
showDeaConsentDialog¶
Future<bool> showDeaConsentDialog(
BuildContext context, {
DeaSdk? sdk,
ConsentCopy copy = const ConsentCopy(),
ConsentDialogStyle style = ConsentDialogStyle.adaptive,
bool remember = true,
bool ask = true,
})
Shows the consent dialog if the user has not answered, records the answer, and returns it.
Returns false without showing anything when the SDK is not initialized.
| Parameter | Description |
|---|---|
sdk |
The SDK instance; defaults to DeaSdk.instance |
copy |
The dialog's text |
style |
adaptive (follows the app theme's platform), material or cupertino |
remember |
Store the answer. false clears any stored answer and asks on every call |
ask |
false returns the stored answer without showing anything |
Widgets¶
DeaConsentDialog¶
const DeaConsentDialog({Key? key, ConsentCopy copy = const ConsentCopy(), ConsentDialogStyle style = ConsentDialogStyle.adaptive})
The dialog itself, for placing inside a flow of your own. It pops its route with true (accept)
or false (decline); record the answer with setConsent.
Types¶
DeaOptions¶
See Options.
EventKind¶
down, move, up, cancel, scroll, hover, keyDown, keyUp. The constant pointerKinds
lists the first six, which is the default for DeaOptions.events.
KeyClass¶
letter, digit, space, delete, navigation, modifier, other.
KeyClass.of(String char) returns the class of one character: letter for a letter in any
script, digit for 0 to 9, space for a space, and other for anything else.
KeyMod¶
Flags for captureKey's mods: KeyMod.ctrl, KeyMod.alt, KeyMod.shift, KeyMod.meta.
Combine with |.
Tool¶
unknown, touch, mouse, pen, trackpad, penInverted.
Force¶
| Field | Type | Description |
|---|---|---|
value |
double |
The pressure reading |
min |
double |
The lowest reading the device reports |
max |
double |
The highest reading the device reports |
Forward the platform's numbers as they are. A device whose min equals max has no pressure
sensor.
Contact¶
| Field | Type | Description |
|---|---|---|
x, y |
double? |
Half-extents of the contact along the screen axes |
major, minor |
double? |
Half-axes of the contact oval |
orientation |
double? |
Direction of the long axis, radians |
Leave a field null when the platform does not measure it; null and 0.0 mean different things.
Target¶
| Field | Type | Description |
|---|---|---|
bucket |
TargetBucket |
unknown, button, link, input, scroller, canvas or background |
id |
int |
A stable 16-bit id for the element; 0 for unknown |
Classification¶
| Field | Type | Description |
|---|---|---|
result |
ClassificationResult |
The answer |
value |
double? |
The human score, from 0 to 1. null exactly when result is insufficient |
actions |
int |
How many scored actions value is based on. For "N more actions" |
botThreshold |
double? |
The model's bot threshold. null when the SDK cannot score |
humanThreshold |
double? |
The model's human threshold. null when the model sets none, or the SDK cannot score |
modelVersion |
int? |
The model the thresholds come from; 0 for the one built in. null when the SDK cannot score |
ClassificationResult¶
Checked in this order:
| Value | When |
|---|---|
insufficient |
The SDK cannot score, or the session has fewer actions than the model asks for (8 with the built-in model). value is null |
human |
value at or above humanThreshold |
bot |
value below botThreshold |
human |
The model sets no humanThreshold, and value is at or above botThreshold |
undetermined |
value lies 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 everyswitchNo humanThreshold,valueat or abovebotThreshold:undeterminedhuman
ThresholdMissing¶
Thrown by getClassification() when the loaded model has no bot threshold.
| Field | Type | Description |
|---|---|---|
modelVersion |
int |
The version of the model without one |
Consent¶
| Member | Type | Description |
|---|---|---|
decision |
ConsentDecision |
unknown, granted or denied |
isAnswered |
bool |
Whether the user has answered |
isGranted |
bool |
Whether the user agreed |
forget() |
Future<void> |
Clears the stored answer so the user is asked again |
addListener(listener) |
void |
Calls listener with the new decision when it changes |
removeListener(listener) |
void |
Stops calling listener |
ConsentCopy¶
| Field | Type | Description |
|---|---|---|
title |
String |
Dialog title |
body |
String |
Explanation |
recorded |
List<String> |
What is recorded; empty hides the section |
notRecorded |
List<String> |
What is never recorded; empty hides the section |
recordedLabel |
String |
Heading for recorded |
notRecordedLabel |
String |
Heading for notRecorded |
closing |
String |
Closing sentence |
accept |
String |
Accept button |
decline |
String |
Decline button |
SessionInfo¶
| Field | Type | Description |
|---|---|---|
session |
String |
Current session id |
device |
Device |
Current device information |
startedAt |
int |
When the current session started, Unix milliseconds |
sdk.version |
String |
SDK version |
sdk.core |
String |
Scoring engine build; none when it did not load |
Device¶
| Field | Type | Description |
|---|---|---|
runtime |
Runtime |
Runtime.flutter |
os |
Os |
Operating system |
surface |
Surface |
Screen size in logical pixels |
pixelRatio |
double |
Physical pixels per logical pixel |
rotation |
int |
Screen rotation: 0, 90, 180 or 270 |
maxTouchPoints |
int |
0: Flutter does not report it |
sensorRate |
int |
The requested motion rate in Hz once motion data has arrived; 0 before that, and while motion is off |
Note: On Flutter,
rotationreads0on every device: the SDK does not read the screen rotation from the platform.
Attestation¶
| Field | Type | Description |
|---|---|---|
supported |
bool |
Whether a key could be created. false also when no appKey was given |
verdict |
Verdict |
passed, failed or unsupported |
platformAttested |
bool |
Whether a Play Integrity (Android) or App Attest (iOS) token went to DEA with the key |
expiresAt |
int? |
Expiry, epoch seconds |
kid |
String? |
Key identifier |
tier |
String? |
Trust tier assigned by DEA |
backing |
String? |
Where the key is kept |
integrity |
String? |
DEA's reading of the device's integrity, decided on DEA's service. null when DEA sends none |
detail |
String? |
Why attestation failed or is unsupported |
Note: DEA's service does not send an
integrityreading at present, sointegrityisnull.
Verdict¶
| Value | When |
|---|---|
passed |
DEA accepted the device key |
failed |
DEA refused the registration or could not be reached, the platform refused to issue its token, or attestation is paused after refused attempts. detail says which |
unsupported |
No key could be created on this device, the SDK's native plugin is not registered, or no appKey was given |
ProofEvent¶
The ad event a proof records. wire is the event_type claim it is signed as.
| Value | wire |
Sent with |
|---|---|---|
adImpression |
ad.impression |
sessionId '', as POST /api/sessions. DEA answers with the ad's session id |
adClick |
ad.click |
DEA's session id, as POST /api/sessions |
adEnded |
ad.ended |
DEA's session id and update: true, as PUT /api/sessions/{sessionId} |
RecordOutcome¶
What sendProof answers.
| Field | Type | Description |
|---|---|---|
accepted |
bool |
Whether DEA accepted the proof (a 2xx status) |
sessionId |
String? |
The session_id in DEA's answer, or null when it named none. For an impression, the id to send the click and the end with |
signed |
SignedProof? |
The proof that was signed, or null when nothing was signed |
isSigned |
bool |
Whether a proof was signed, whether or not DEA accepted it |
said |
String? |
DEA's answer when it accepted the proof; otherwise why nothing was signed, or why it was not delivered. For a person to read. See Ads |
SignedProof¶
What getProof answers, and RecordOutcome.signed.
| Field | Type | Description |
|---|---|---|
proof |
String |
The compact JWS, header.claims.signature: what goes to DEA as h_proof |
header |
Map<String, Object?>? |
The signed header, decoded: alg, typ, kid |
claims |
Map<String, Object?>? |
The signed claims, decoded |
signature |
String? |
The signature segment, base64url |
score |
double |
The score signed in (h_score), from 0 to 1 |
evidenceAt |
int |
When the evidence behind score was gathered, Unix seconds (h_ts) |
windows |
int |
How many scored actions score is based on (h_wc) |
modelVersion |
int? |
The model that scored (h_mv); 0 for the one built in. null when the proof carries none |
sessionId |
String |
The session_id signed in |
event |
ProofEvent |
The event signed in |