Skip to content

DEA SDK for React Native

Detect whether an app session comes from a real person. The SDK observes touch and device-motion input across your whole React Native app, natively on Android and iOS, and scores the session on the device.

On this page: Prerequisites · Install · Initialize the SDK · Ask for consent · Use the classification · Verify your setup · Before you release · Next steps

Prerequisites

  • An appId and appKey for each platform's app — see Accounts and keys. On Android, also the Google Cloud project number DEA issued for Play Integrity — see Attest.
  • React Native 0.76 or later, with the New Architecture enabled. The SDK is a TurboModule and does not load on the old architecture.
  • Android: minSdkVersion 24 (Android 7.0) or later
  • iOS: deployment target 15.1 or later

The SDK runs on Android and iOS. Other React Native targets (web, Windows, macOS) are not supported: init rejects there.

Expo

Expo Go is not supported. The SDK contains native code that is not part of Expo Go.

The package ships no Expo config plugin, so npx expo prebuild does not add the iOS and Android setup described below to the native projects it generates.

Install

Not available yet. @dea/react-native is not published: it is not on the npm registry, and the 0.19.0 release lists no React Native package. The package also needs DEA's native Android and iOS SDKs at its own version, and neither of those can be installed either: DEA's Maven repository (https://sdk.dep-protocol.com/maven) serves ai.dea:dea-sdk 0.2.2 only, and no podspec or Swift package of the native iOS SDK is published. No install command for React Native works at this release.

The JavaScript package wraps DEA's native Android and iOS SDKs. React Native's autolinking links both native halves. Each half depends on the native SDK at the same version as @dea/react-native.

iOS setup

Not available yet. The iOS half of the package depends on the DeaSDK pod (which depends on DeaBase). Neither pod is on the CocoaPods trunk or in any published spec repository, so pod install cannot resolve them.

The package's pod requires an iOS deployment target of 15.1 or later.

Android setup

Not available yet. The Android half of the package depends on ai.dea:dea-sdk at the same version as @dea/react-native, resolved from the repositories your app declares. DEA's Maven repository serves 0.2.2 only, and the artifact is not on Maven Central, so Gradle cannot resolve it.

The native Android SDK declares the INTERNET permission, which Android's manifest merger adds to your app.

Initialize the SDK

Initialize once, as early as possible — at the top level of your entry file or in your root component's first effect — so that capture covers the whole session.

import {useEffect} from 'react';
import * as Dea from '@dea/react-native';
import {Root} from './Root';

export default function App() {
  useEffect(() => {
    Dea.init({appId: 'YOUR_APP_ID'}).then(started => {
      if (!started.ready) {
        console.warn('DEA cannot score:', started.coreFault);
      }
    });
  }, []);

  return <Root />;
}
  • Every call returns a promise, including the cheap ones. Await them when the order matters.
  • init is safe to call more than once. A repeat call returns the running session and keeps its options.
  • init does not fail when the scoring engine cannot start. The SDK keeps capturing, started.ready is false, and started.coreFault says why.
  • Capture is global: every touch in the app, the motion sensors, and the app lifecycle. There is no component to wrap your app in and nothing to register per screen.
  • Every other call except deaTarget, getTargetTally and onAttestationEvent rejects until init has run.
  • Nothing is recorded until the user consents. See the next step.

Note: Pass appKey to init as well — the key of the platform the build is for. Reading the classification does not need it: scoring runs on the device. Without it, with a production appId, attest() resolves unsupported without contacting DEA. See Accounts and keys for what the key is for.

By default the SDK records nothing until the user agrees. This step is required: an app that never asks collects no data and never gets a classification.

The React Native SDK has no built-in consent dialog. Ask with your own UI, then record the answer:

import {Alert} from 'react-native';
import * as Dea from '@dea/react-native';

export async function askForConsent(): Promise<void> {
  if ((await Dea.getConsent()) !== 'unknown') return; // already answered

  Alert.alert(
    'Help us keep bots out',
    'We measure how you touch and hold your phone to tell people apart from bots. We never record what you type or what is on your screen.',
    [
      {text: 'Not now', style: 'cancel', onPress: () => Dea.setConsent(false)},
      {text: 'Allow', onPress: () => Dea.setConsent(true)},
    ],
  );
}

The answer is stored on the device, so the question only needs to be asked once. If you already asked before init, pass the answer to init instead — see User Consent. What the SDK captures, and what it never reads, is on Privacy and network.

Use the classification

Read the classification at the moment you make a decision. The read is fast and local: it does not call the network.

import * as Dea from '@dea/react-native';

async function onSignUp(form: SignUpForm) {
  const {result} = await Dea.getClassification();
  if (result === 'human') {
    await submitSignUp(form);
  } else {
    showChallenge(); // 'bot', 'undetermined' or 'insufficient': a captcha, a delay, a manual review
  }
}

The thresholds come from the loaded model, never from your app. insufficient and undetermined are answers in their own right, and your app decides what each allows. insufficient means the session is not sufficient yet, because it has fewer actions than the model asks for (8 with the built-in model, see Evidence); value is null then. undetermined means the score is between the two thresholds. See How scoring works.

Verify your setup

  1. Check the SDK from code after init:
const started = await Dea.init({appId: 'YOUR_APP_ID'});
console.log('ready:', started.ready);        // true
console.log('fault:', started.coreFault);    // null
console.log('sdk:', started.sdkVersion);

const info = await Dea.getSessionInfo();
console.log('session:', info.session);       // a UUID
  1. Grant consent, use the app — tap, scroll, swipe — for at least 8 actions, then read the classification:
console.log(await Dea.getConsent());  // 'granted'
console.log(await Dea.getClassification());
// { result, value, actions, botThreshold, humanThreshold, modelVersion }

result leaves 'insufficient' once actions reaches the number the model asks for: 8 with the built-in model.

  1. On Android, you can also turn on debug and watch Logcat:
adb logcat | grep "dea"

You should see one [dea] … line per captured event after consent is granted. If you see nothing after touching the screen, see Troubleshooting.

Turn debug off before you ship.

Before you release

  • [ ] debug is false
  • [ ] Your consent flow calls setConsent, or passes consent to init — see User Consent
  • [ ] The classification is read at the decision point, with a fallback for bot, undetermined and insufficient — see Human Scoring
  • [ ] Your main controls are named with deaTarget — see Name your views
  • [ ] Capture is paused on password and payment screens — see Sensitive Screens
  • [ ] reset() is called on logout — see Sessions
  • [ ] Your privacy policy covers what the SDK captures and sends — see Privacy and network and Going to production

Next steps