Getting started: React Native (Validations plugin)

Introduction

The Truora React Native plugin allows you to integrate identity verification features directly into your React Native mobile applications. The plugin bridges to native implementations on both Android and iOS platforms, handling the complexity of capturing the user’s identity documents, facial recognition, and liveness detection to verify their identity against backend records.

Requirements

Platform Requirements

  • React Native: 0.70.0 or higher (New Architecture supported)

  • TypeScript: 5.0 or higher (recommended)

  • Android: API Level 21 (Android 5.1) or higher

  • iOS: 13.0 or higher

Permissions Required

  • Camera access for document and face capture

  • Internet access for API communication

Expo Compatibility

This plugin requires native code and is not compatible with Expo Go. If your project uses Expo, you can use EAS Build to create development and production builds that include native modules.

Prerequisites & Authentication

The Key Provider Interface

To prevent hardcoding sensitive logic, you must implement the TruoraAPIKeyGetter interface in your code. This allows you to retrieve the temporary generated API key from a secure location (like a compiled secret, a secure storage enclave, or an obfuscated string). This interface is how the sdk will get access to the api key for the validations, the resulting api key must be of type ‘sdk’ (temporary), any other key type will result in an error.

Sample Typescript Implementation

import EncryptedStorage from 'react-native-encrypted-storage';
import Config from 'react-native-config';

// Option 1: From encrypted storage
const getApiKeyFromSecureStorage = async (): Promise<string> => {
  const apiKey = await EncryptedStorage.getItem('truora_api_key');
  if (!apiKey) {
    throw new Error('API key not found in secure storage');
  }
  return apiKey;
};

// Option 2: From environment config (less secure, for development)
const getApiKeyFromSecureStorage = (): string => {
  return Config.TRUORA_API_KEY || '';
};

// Option 3: From backend service
const getApiKeyFromSecureStorage = async (): Promise<string> => {
  const response = await fetch('https://your-api.com/truora-key', {
    headers: { Authorization: `Bearer ${userToken}` },
  });
  const { apiKey } = await response.json();
  return apiKey;
};

Configuration Options

Before implementing validations, let’s understand the available configuration options.

Using custom validation config and UI config is optional when building the validation:

  • If no uiConfig is provided then the validation view will show the standard Truora branding, logo and colors
  • If no validationConfig is provided then default values will be applied like:
    • No waiting for validation results before finishing the validation process for the user
    • autocapture of face/doc when it’s detected will be on

More indepth information on the validation configuration options, such as similarity threshold, can be found in the official validations api documentation

User ID

The userId parameter is crucial for initializing the Truora SDK. It provides a unique identifier for the user undergoing the validation process.

  • Purpose: The userId allows Truora to associate validation attempts and reference data (like previously captured reference faces) with a specific user in your system. It is mandatory for linking the validation results to your user base.

  • Best Practice: This ID should be an immutable, non-sensitive identifier from your database (e.g., a UUID or internal user ID) that uniquely identifies the person. Do not use sensitive PII like an email address or national ID number as the userId.

Language

The language parameter allows you to define the localization of the text and instructions displayed within the validation view.

  • Customization: By setting the language, you ensure a user-friendly experience by presenting instructions and feedback in the user’s preferred language.

  • Available Options: The SDK supports several languages. You should provide the language code as a two-letter string (e.g., “es” for Spanish, “en” for English, “pt” for Portuguese). If no language is provided, the SDK will typically default to English or attempt to use the device’s system language, though providing an explicit language is recommended.

Example in Initialization:

await TruoraSDK.initialize({
  "getApiKeyFromSecureStorage": getApiKeyFromSecureStorage,
  "userId": userId, // <-- The unique identifier for the user
  "ui": { /* ... */ },
  "validation": { /* ... */ },
  "language": "es" // <-- Sets the UI language to Spanish
});

Face Validation Configuration

The FaceValidationConfig allows you to customize face capture and validation behavior:

const faceConfig: FaceValidationConfig = {
  type: "face",

  // Capture settings
  useAutocapture: true,        // Auto-capture when face is detected
  similarityThreshold: 0.8,       // Matching strictness (0.0 - 1.0)
  timeout: 60,                  // Timeout in seconds

  // Result handling
  waitForResults: true,           // Wait for API response before closing

  // Optional: Reference face for comparison if not provided
  // one associated with the user id on Truora is used if any.
  referenceFace: 'https://example.com/reference.jpg',
};

Configuration Parameters:

Parameter Type Default Description
type ValidationType - Always Face for face validation. Required.
useAutocapture bool true Automatically capture when face is properly detected
similarityThreshold double 0.8 Minimum similarity score required (0.0 - 1.0)
timeout int 60 Maximum time in seconds for the validation
waitForResults bool false Wait for API response before closing the view and show results to the user
referenceFace ReferenceFace null Optional reference image for comparison

Document Validation Configuration

The DocumentValidationConfig allows you to customize document capture:

const documentConfig: DocumentValidationConfig = {
  type: "document",

  // Document details (optional - if not set, a selection screen will be shown)
  country: Country.co,         // Country code (e.g., 'CO', 'MX', 'PE')
  documentType: DocumentType.nationalId,      // Type of document

  // Capture settings
  useAutocapture: true,    // Auto-capture when document is detected
  timeout: 90,         // Timeout in seconds

  // Result handling
  waitForResults: true,       // Wait for API response before closing
};

Configuration Parameters:

Parameter Type Default Description
type ValidationType - Always Document for document validation. Required.
country Country null Country code for document validation (if not set, user selects)
documentType DocumentType null Type of document (if not set, user selects)
useAutocapture bool true Automatically capture when document is detected
timeout int 90 Maximum time in seconds for the validation
waitForResults bool false Wait for API response before closing the view and show results to the user

Available Countries and Document Types:

Country Code Supported Document Types
Argentina Country.ar nationalId
Brazil Country.br cnh, generalRegistration
Chile Country.cl nationalId, foreignId, driverLicense, passport
Colombia Country.co nationalId, foreignId, rut, ppt, passport, identityCard, temporaryNationalId
Costa Rica Country.cr nationalId, foreignId
El Salvador Country.sv nationalId, foreignId, passport
Mexico Country.mx nationalId, foreignId, passport
Peru Country.pe nationalId, foreignId
Venezuela Country.ve nationalId
All Country.all passport

Understanding SDK Results

Before implementing validations, it’s important to understand what results you’ll receive and how to handle them.

The SDK returns a TruoraValidationResult which can be:

  • completed: Validation process finished (contains ValidationResult)
  • canceled: Validation process canceled by the user (could contain ValidationResult)
  • error: SDK error occurred (contains TruoraException)

Validation Result Object

The plugin returns ValidationResult objects with the following structure:

type ValidationStatus = 'success' | 'failure' | 'pending';
type ValidationType = 'face' | 'document';

interface ValidationResult {
  validationId: string; // Unique identifier for this validation
  status: ValidationStatus; // Status of the validation
  type: ValidationType; // Type of the validation
}

Validation Statuses

Status Description When it occurs
ValidationStatus.success Validation passed User successfully passed the validation
ValidationStatus.failure Validation failed User did not pass the validation criteria
ValidationStatus.pending Awaiting processing Validation is being process

TruoraException Types

When the SDK returns failed, the error can be one of three types:

Exception Type Description
TruoraException.sdk Internal SDK error (configuration, permissions, user actions)
TruoraException.validationApi Error from the Truora Validation API
TruoraException.network Network connectivity error

Common SDK Error Types (SDKErrorType):

Error Type Code Description
cameraPermissionError 20011 Camera permission was denied
invalidApiKey 20017 API key is invalid or expired
invalidConfiguration 20024 SDK configuration is invalid
networkError 20025 Network connection failed
uploadFailed 20026 Failed to upload captured media

Handling Example

const handleResult = (result: TruoraValidationResult) => {
  switch (result.type) {
    case 'completed':
      // Validation process completed - check the validation status
      const validation = result.validation;
      console.log('Validation ID:', validation.validationId);
      console.log('Status:', validation.status);
      console.log('Type:', validation.type);

      if (validation.status === 'success') {
        // User passed the validation
        navigation.navigate('Success');
      } else if (validation.status === 'failure') {
        // User did not pass the validation criteria
        showRetryDialog();
      }
      break;

    case 'canceled':
      // User cancelled - just go back
      navigation.goBack();
    break;

    case 'error':
      // SDK error occurred - handle based on error type
      handleError(result.error);
      break;
  }
};

const handleError = (error: TruoraException) => {
  switch (error.type) {
    case 'sdk':
      // Handle SDK errors 
      if (error.code === 20011) {
        // Camera permission denied
        showPermissionDialog();
      } else {
        showErrorDialog(error.message);
      }
      break;

    case 'network':
      showErrorDialog(`Connection error: ${error.message}`);
      break;

    case 'validationApi':
      showErrorDialog(`API error: ${error.message}`);
      break;
  }
};

Implementation

Now that you understand configurations and result handling, let’s implement validations.

Basic Face Validation

Here’s a complete example of implementing face validation in Flutter:

import React, { useEffect, useState } from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  StyleSheet,
  Alert,
  ActivityIndicator,
} from 'react-native';
import TruoraSDK, {
  FaceValidationConfig,
  UIConfig,
  ValidationResult,
  ValidationError,
} from 'truora-validations-react-native';
import Config from 'react-native-config';

const ValidationScreen: React.FC = () => {
  const [isValidating, setIsValidating] = useState(false);
  const [validationStatus, setValidationStatus] = useState('Ready to start validation');

  // Initialize SDK on mount
  useEffect(() => {
    initializeSDK();
  }, []);

  const initializeSDK = async () => {
      const getApiKeyFromSecureStorage = () => Config.TRUORA_API_KEY; // Or fetch from secure storage
      const userId = "my-unique-user-identifier";
    try {
      await TruoraSDK.initialize({
  "getApiKeyFromSecureStorage": getApiKeyFromSecureStorage,
  "userId": userId,
  "ui": {
      primaryColor: '#435AE0',
      surfaceColor: '#FFFFFF',
      errorColor: '#FF5454',
      logoUrl: 'https://your-cdn.com/logo.png',
    },
  "validation": {
      type: "face",
      useAutocapture: true,
      similarityThreshold: 0.8,
      timeout: 60,
      waitForResults: true,
    },
  "language": "es"
});
    } catch (error) {
      setValidationStatus(`Initialization failed: ${error}`);
    }
  };

  const startFaceValidation = async () => {
    setIsValidating(true);
    setValidationStatus('Starting face validation...');

    // Start the validation
    const result = await TruoraSDK.start();
    setIsValidating(false);
    handleResult(result);
  };

  const handleResult = (result: TruoraValidationResult) => {
    switch (result.type) {
      case 'completed':
        const validation = result.validation;
        if (validation.status === 'success') {
          setValidationStatus(`Success! ID: ${validation.validationId}`);
        } else if (validation.status === 'failure') {
          setValidationStatus('Validation failed. Please try again.');
        } else {
          setValidationStatus('Processing...');
        }
        break;
      case 'canceled':
      	  // User cancelled - just go back 
        navigation.goBack();

	  break;
      case 'error':
        setValidationStatus(`Error: ${result.error.message}`);
        if (result.error.code === 20011) {
          Alert.alert(
            'Camera Permission Required',
            'Please grant camera permission to continue with identity verification.',
            [{ text: 'OK' }]
          );
        }
        break;
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.statusText}>{validationStatus}</Text>

      <TouchableOpacity
        style={[styles.button, isValidating && styles.buttonDisabled]}
        onPress={startFaceValidation}
        disabled={isValidating}
      >
        {isValidating ? (
          <ActivityIndicator color="#FFFFFF" />
        ) : (
          <Text style={styles.buttonText}>Start Face Validation</Text>
        )}
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  statusText: {
    fontSize: 16,
    textAlign: 'center',
    marginBottom: 40,
  },
  button: {
    backgroundColor: '#435AE0',
    paddingHorizontal: 32,
    paddingVertical: 16,
    borderRadius: 8,
    minWidth: 200,
    alignItems: 'center',
  },
  buttonDisabled: {
    opacity: 0.6,
  },
  buttonText: {
    color: '#FFFFFF',
    fontSize: 16,
    fontWeight: '600',
  },
});

export default ValidationScreen;

Document Validation

For document validation, use the DocumentValidationConfig:

import TruoraSDK, {
  DocumentValidationConfig,
  UIConfig,
} from 'truora-validations-react-native';

const startDocumentValidation = async () => {
  // Start the validation
  const result = await TruoraSDK.start();
  handleResult(result);
};

Troubleshooting

Common Issues

  1. Camera not working on Android
    Solution: Verify that camera permissions are added to AndroidManifest.xml and that the user has granted permission at runtime.

  2. Build fails on iOS
    Solution: Run cd ios && pod install and ensure your iOS deployment target is set to 13.0 or higher in both Podfile and Xcode project settings.

  3. API Key Invalid" error
    Solution: Verify your API key is correct and has the proper grants (sdk type). Check that it hasn’t expired.

  4. Validation timeout in completed results
    Solution: Increase the timeout value in the config, or ensure the device has a stable internet connection.