Troubleshooting¶
init throws TypeError: crypto.randomUUID is not a function¶
Cause: The page is not a secure context — it is served over plain HTTP from a host other than
localhost — or the browser is older than the
minimum versions. Browsers provide crypto.randomUUID() only on secure
pages, and the SDK needs it to start a session.
Solution: Serve the page over HTTPS, or from localhost during development. To keep a page
working in a browser the SDK does not support, call init inside a try block.
getClassification() always returns 'insufficient'¶
Cause: One of the following:
- The session has fewer actions than the model asks for. With the built-in model, a desktop
browser needs 20, from at least two kinds of input (pointer, scroll, keyboard) with at least
three each, and a browser on a phone or tablet needs 8 — see
Evidence. A user who only clicks gives one kind
of input: on a desktop, the result stays
'insufficient'until they also scroll or type. - Capture was paused and never resumed.
- The consent gate is on (
requireConsent: true) andsetConsent(true)was never called. - The scoring engine failed to load:
dea.erroris set.
Solution: Check each in turn:
import { DeaSdk } from '@dea/sdk';
const dea = DeaSdk.current!;
console.log(dea.consent.decision); // 'granted' is needed when requireConsent is on
await dea.ready(); // waits for consent when requireConsent is on
console.log(dea.error); // not null: the engine failed to load — see below
console.log(dea.getClassification()); // result, value, actions and both thresholds
Make sure every pause() has a matching resume().
getClassification() always returns 'undetermined'¶
Cause: There are enough actions, and the score lies between botThreshold and
humanThreshold. A model that sets no humanThreshold has no such band: a score is then 'bot' or
'human'.
Solution: This is the model's answer for this user, not a fault. Take your fallback path, such as a challenge or a manual review.
getClassification() throws ThresholdMissing¶
Cause: The loaded model has no bot threshold. Its version is on the error's modelVersion.
Solution: Catch the error where you read the classification and take your fallback path, as
for 'undetermined'. Report the modelVersion to DEA: the model comes from DEA, not from your
configuration.
import { DeaSdk, ThresholdMissing, type ClassificationResult } from '@dea/sdk';
function readResult(): ClassificationResult {
try {
return DeaSdk.current?.getClassification().result ?? 'insufficient';
} catch (error) {
if (error instanceof ThresholdMissing) return 'undetermined';
throw error;
}
}
dea.error is set after ready()¶
Cause: The SDK's WebAssembly scoring engine could not load. dea.error is a CoreLoadError;
its reason says why:
reason |
Cause |
|---|---|
'core_not_loaded' |
The engine could not be fetched or compiled. Usually a Content Security Policy blocks it, or coreUrl points at a file that cannot be fetched |
'core_abi_mismatch' |
coreUrl points at an engine from a release this package cannot read |
'core_wrong_profile' |
coreUrl points at the engine for the other profile (desktop or mobile) |
Solution: Read dea.error.message, which names the blocked request or the mismatch, and the
browser console, which reports a Content Security Policy violation.
- Blocked by CSP: allow
data:inconnect-src(or thecoreUrlyou set), and'wasm-unsafe-eval'inscript-src. See Content Security Policy. - 404 or a mismatch: check
coreUrl, or remove it to use the engine embedded in the package.
The staging package also logs this as sdk.core_failed, with the same reason.
init options are ignored¶
Cause: init was already called. A later call returns the running instance and ignores its
options.
Solution: Call init once, as early as possible. If you really need different options, call
DeaSdk.current?.dispose() first.
attest() returns unsupported¶
Cause: The browser could not create a signing key: it refuses IndexedDB (common in private browsing), or it has no Web Crypto.
Solution: Nothing in the page can create the key in such a browser. Scoring still works; only attestation and ad proofs are unavailable.
attest() returns failed¶
Cause: One of the following:
- A production
appIdwith noappKey: the SDK makes no request. - DEA refused the key registration — for example because
appKeyis not the key issued with thisappId. - DEA could not be reached: no network, or your Content Security Policy blocks
https://poh-api.dep-protocol.com.
Solution: Check DeaSdk.current?.appKey is the key DEA issued with your appId — see
Accounts and keys — and allow DEA in your
Content Security Policy. The staging package logs the refusal
as attest.failed with a reason, such as app_key_invalid or app_key_missing. A failed result
is not cached: call attest() again to retry.
ads.session_opened() resolves null¶
Cause: One of the following:
- The classification is still
'insufficient': no proof is signed until it is not, so the impression is not recorded. An ad shown at page load, before the user has interacted, is in this case. - No
appKey, or no browser key. - A browser key DEA has not registered.
- DEA could not be reached.
Solution: For cause 1, check getClassification().result before you open the ad session, and
open it once it is no longer 'insufficient', while the ad is still on screen. Otherwise, call attest() and check
it answers 'passed' before opening an ad session. To learn which cause it was, compare
ads.counts before and after the call — see
Find out why no ad session opened.
ad.click() returns false¶
Cause: One of the following:
end()was already called, or a click was already accepted for this ad session.- An element was passed to
session_opened(), and no press or release landed inside it before the click.
Solution: For cause 2, make sure the element passed to session_opened() is the one the ad
renders into, and that it is visible and not zero-sized. Presses inside an iframe never reach the
SDK: for a creative rendered in an iframe, open the session without an element. Presses made while
capture is paused, or before the user consented, are not seen either.
Nothing appears in the console¶
Cause: The production package carries no log.
Solution: While you integrate, install the staging package — see
Verify your setup. It logs INFO, WARN and ERROR entries.