Skip to content

Options

Pass options once, to init. They are read when the SDK starts. Passing different options to a later init call has no effect, because the running instance is returned.

import { init, CaptureEvent, Profile } from '@dea/sdk';

const dea = init({
  appId: 'YOUR_APP_ID',
  appKey: 'YOUR_APP_KEY',
  profile: Profile.Desktop,
  events: [CaptureEvent.PointerDown, CaptureEvent.PointerUp, CaptureEvent.Wheel],
  motionRate: 0,
  targets: false,
  requireConsent: true,
  modelUpdates: true,
  onLog: (entry) => myPanel.add(entry),
  logLevel: 'info',
});

myPanel stands for your own code.

Core options

appId

Type Default Required
string 'unknown-app' Yes

Your DEA application id, issued with appKey — see Accounts and keys. The SDK signs it into every proof, and reads its prefix to know whether it runs for a production app; see How the SDK reads an appId. Always pass it: the default is a placeholder that runs as a production app DEA has not registered.

appKey

Type Default Required
string none Yes, for Attest and Ads

The app key DEA issued together with appId. The SDK sends it in the X-App-Key header of its requests to DEA's service: attest() and ad proofs. Model downloads carry no key. It identifies the app and is not a secret.

Without it, on a production appId, attest() answers 'failed' without making a request, and every ad proof is refused before it is signed, so ads.session_opened() resolves null. Scoring and getClassification() work either way. dea.appKey reads back the key in use, or null when there is none.

Logging options

What the SDK logs is decided by the package you install, not by an option. The production package carries no log at all. The staging package — the same SDK with the log switched on, for use while you integrate (see Verify your setup) — logs INFO and above. Each entry is one state change — the SDK started, a device key was registered, a proof was accepted — in the same form on every platform.

Package Levels written
production none
staging INFO, WARN, ERROR

Every entry is written to the browser console as one line:

dea 2026-10-16T01:39:29.731Z INFO  sdk.ready                      ok      session.id=ee0962fd-… core=web-desktop profile=web-desktop | SDK ready: core web-desktop, profile web-desktop

onLog

Type Default Required
(entry: LogEntry) => void none No

Called with every entry, as JSON with OpenTelemetry field names: timestamp, severityText, severityNumber, eventName, body, attributes, resource. Use it for a log panel or to forward entries to your own logger. The SDK never sends an entry anywhere itself. On the production package it is never called.

import { init } from '@dea/sdk';

init({
  appId: 'YOUR_APP_ID',
  appKey: 'YOUR_APP_KEY',
  onLog: (entry) => myLogger.log(entry.severityText, entry.eventName, entry.attributes),
});

formatLine(entry), exported by the package, renders an entry as the console line above.

logLevel

Type Default Required
'debug' \| 'info' \| 'warn' \| 'error' \| 'off' 'debug' No

Raises the level entries are written from. It can only quiet the package's own levels, never add one: logLevel: 'warn' on the staging package drops INFO, and nothing turns logging on in the production package.

Capture options

profile

Type Default Required
Profile Detected No

Whether the page is treated as a desktop or a mobile browser. The profile decides which input is captured, whether motion sensors are requested, and which scoring engine scores the session. Detection picks Profile.Mobile when the browser reports a coarse pointer ((pointer: coarse)) and at least one touch point, and Profile.Desktop otherwise.

Profile Captures Motion sensors
Profile.Desktop ('web-desktop') Pointer, wheel, physical keyboard (keydown, keyup) No
Profile.Mobile ('web-mobile') Pointer, wheel, on-screen keyboard (beforeinput) Yes

When the page always serves one kind of device, import the matching entry point instead of passing profile. It skips detection:

import { init } from '@dea/sdk/desktop'; // or '@dea/sdk/mobile'

Note: On iPhone and iPad, browsers deliver motion data only after the user allows it. With Profile.Mobile, the SDK asks the browser for that permission when the user first taps the page, and the browser shows its own prompt. To never ask, pass motionRate: 0.

events

Type Default Required
CaptureEvent[] Set by the profile No

The input events to capture. Overrides the profile's list. Capturing fewer kinds reduces work on the page but also reduces the evidence the classification is built on.

Value Browser event
CaptureEvent.PointerDown pointerdown
CaptureEvent.PointerMove pointermove
CaptureEvent.PointerUp pointerup
CaptureEvent.PointerCancel pointercancel
CaptureEvent.Wheel wheel
CaptureEvent.KeyDown keydown
CaptureEvent.KeyUp keyup
CaptureEvent.BeforeInput beforeinput (typing only: not a paste, a drop or an autocorrect)

Do not list BeforeInput together with KeyDown or KeyUp: typing on a physical keyboard fires both, and each keystroke would be recorded twice. From any key event the SDK records only the kind of key (a letter, a digit, a space…), the modifier keys held and its timing, never the character, and nothing at all from a keystroke in an <input type="password">.

motionRate

Type Default Required
number (Hz) 50 on mobile, 0 on desktop No

0 turns motion capture off: the SDK neither listens for devicemotion nor asks for permission. Any other value turns it on. Browsers deliver devicemotion at a rate of their own choosing, which this option does not change; the value is recorded as the session's sensor rate and reported in getSessionInfo().device.sensor_rate once the first reading arrives (0 until then). Values below 25 are raised to 25.

targets

Type Default Required
boolean false No

Records what kind of element each press landed on — a button, a link, an input, a scroll area, a canvas. Only the category is recorded, never the element's text or attributes. Resolving the category asks the browser for layout information once per press, so it is opt-in.

requireConsent

Type Default Required
boolean false No

Turns on the consent gate: nothing is recorded or scored, and no scoring model is downloaded, until the page calls setConsent(true). See User Consent.

consentStore

Type Default Required
ConsentStore The browser's localStorage, under the key deapnetwork.consent No

Where the user's answer is kept between visits: an object with read(), which returns 'unknown', 'granted' or 'denied', and write(decision). Pass your own to keep the answer beside your consent platform's record. memoryConsentStore() keeps it for the current page only.

Model options

modelUpdates

Type Default Required
boolean true No

Whether the SDK keeps its scoring model current. On, every init asks https://sdk.dep-protocol.com whether DEA has published a newer model for this profile, after the SDK is ready and without delaying anything. A newer model is downloaded, verified inside the SDK — it must be signed by DEA and newer than the one running — and kept in the browser's IndexedDB for the next visit. With requireConsent: true, the check waits until the user agrees. Off, the SDK deletes any model it kept, makes no request, and scores with the model built into the package.

dea.model() reports the model in use: { version, source }, where source is 'embedded', 'cache' or 'network'.

Loading options

coreUrl

Type Default Required
string \| URL The engine embedded in the package No

Where to load the SDK's WebAssembly scoring engine from. By default it is embedded in the package's JavaScript as a data: URL: there is no .wasm file to copy or host, and you do not need this option. Set it only when your Content Security Policy cannot allow data: in connect-src; allow the URL you set instead (see Content Security Policy).

The file at the URL must be the engine built for the profile the session runs on, from the same release as the package. The SDK refuses a file built for the other profile, or one this release cannot read, and reports it on dea.error. One URL serves one profile, so pin the profile when you set it.

Note: DEA's release publishes only the mobile-profile engine as a file of its own: https://sdk.dep-protocol.com/0.19.0/core/wasm32-unknown-unknown/dea_core.wasm. Use it with @dea/sdk/mobile or profile: Profile.Mobile, either at that URL, which DEA serves to any origin, or copied to your own host. The desktop-profile engine is not published as a separate file, so there is no file to point coreUrl at for a desktop session.

Options a production appId ignores

DeaConfig also declares integrations, core, attest, ads and model. They are for DEA's own testing and are not part of the production integration: leave them unset. On a production appId the SDK ignores them.