npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-usesense

v1.0.0

Published

React Native plugin for human presence verification. Wraps the native UseSense iOS and Android SDKs.

Readme

UseSense React Native

React Native plugin for human presence verification. Wraps the native UseSense iOS and Android SDKs into a single cross-platform package.

UseSense verifies that a real human — not a bot, deepfake, or replay attack — is behind the camera during identity verification sessions. Three independent pillars run in parallel on every session:

  • DeepSense (Channel & Device Integrity): Platform attestation, runtime integrity, capture pipeline analysis. Produces a channelTrustScore (0-100).
  • LiveSense (Multimodal Proof-of-Life): Facial dynamics, visual integrity, presentation attack detection, audio deepfake detection. Produces a livenessScore (0-100).
  • MatchSense (Identity Collision Detection): 1:N face search (enrollment), 1:1 face verification (authentication), cross-identity risk scoring. Produces a matchSenseRiskScore (0-100).

A fused presenceConfidence score and a final decision (approved / rejected / manual_review) are returned. The definitive verdict is delivered via HMAC-SHA256 signed webhook to your backend. The SDK result is for UI feedback only and must never be trusted for access-control decisions.

Requirements

  • React Native 0.73+ (New Architecture supported; Old Architecture via interop layer)
  • iOS 14.0+
  • Android API 24+ (Android 7.0)
  • Xcode 15.0+
  • Node.js 18+
  • Device with front-facing camera (required on both platforms)

Installation

npm install react-native-usesense
# or
yarn add react-native-usesense

iOS Setup

cd ios && pod install

The native UseSense iOS SDK is installed automatically as a CocoaPod dependency.

Add required permissions to your Info.plist:

<key>NSCameraUsageDescription</key>
<string>UseSense needs camera access to verify your identity.</string>

<!-- Only if enableAudio is true -->
<key>NSMicrophoneUsageDescription</key>
<string>UseSense needs microphone access for voice verification.</string>

<!-- Optional, improves DeepSense accuracy -->
<key>NSMotionUsageDescription</key>
<string>UseSense uses motion data to improve verification accuracy.</string>

Android Setup

The native UseSense Android SDK is pulled automatically via Maven Central.

Add required permissions to your AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- Only if enableAudio is true -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

No additional Gradle configuration needed. Auto-linking handles registration.

New Architecture

The plugin supports React Native's New Architecture (Turbo Modules) out of the box. If your project has the New Architecture enabled, the plugin uses the Turbo Module path automatically. No configuration needed.

For projects still on the Old Architecture (Bridge), the plugin includes an interop layer and works without changes.

Quick Start

import { UseSense } from 'react-native-usesense';

// 1. Initialize (once, e.g. in App.tsx or app entry)
await UseSense.initialize({
  apiKey: 'your_sandbox_api_key',
  environment: 'sandbox',
});

// 2. Run a verification session
try {
  const result = await UseSense.startSession({
    sessionType: 'enrollment',
  });
  console.log('Decision:', result.decision);
  console.log('Liveness:', result.livenessScore);
  console.log('Channel Trust:', result.channelTrustScore);
  console.log('MatchSense Risk:', result.matchSenseRiskScore);
} catch (error) {
  console.error('Verification failed:', error.code, error.message);
}

// The definitive verdict arrives at your backend via webhook.
// The SDK result is for UI feedback only.

Configuration

Full reference for UseSenseConfig:

| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | apiKey | string | Yes | — | Your API key from the UseSense dashboard | | environment | 'production' \| 'sandbox' | No | 'sandbox' | Target environment | | organizationId | string | No | — | Organization ID (inferred from API key) | | sessionType | 'enrollment' \| 'authentication' | No | 'enrollment' | Default session type | | identityId | string | No | — | Identity ID for authentication sessions | | challengePolicy | 'standard' \| 'enhanced' \| 'adaptive' | No | 'standard' | Challenge difficulty policy | | enableAudio | boolean | No | false | Enable audio capture for voice deepfake detection | | timeout | number | No | 60000 | Maximum session duration in milliseconds | | metadata | Record<string, string> | No | — | Custom key-value pairs attached to session |

Session Types

Enrollment

First-time face registration. The system indexes the user's face, performs a 1:N duplicate scan via MatchSense, and creates an identity record if approved.

const result = await UseSense.startSession({
  sessionType: 'enrollment',
});

if (result.decision === 'approved') {
  // Identity created. Store result.sessionId for reference.
  console.log('Enrollment approved. Presence confidence:', result.presenceConfidence);
}

Authentication

Returning user claims an existing identity. The system performs 1:1 verification against the enrolled template, plus a 1:N cross-identity scan.

const result = await UseSense.startSession({
  sessionType: 'authentication',
  identityId: 'idn_abc123', // required for authentication
});

if (result.decision === 'approved') {
  console.log('Identity verified');
}

Handling Results

UseSenseResult contains the full verification breakdown:

| Field | Type | Description | |-------|------|-------------| | sessionId | string | Unique session identifier | | decision | 'approved' \| 'rejected' \| 'manual_review' | Verification decision | | channelTrustScore | number | DeepSense channel integrity score (0-100). Higher is more trusted. | | livenessScore | number | LiveSense liveness score (0-100). Higher means more likely live. | | matchSenseRiskScore | number | MatchSense risk score (0-100). Lower is better. | | presenceConfidence | number | Fused presence confidence (0-100). Higher is more confident. | | reasons | string[] | Reasons contributing to the decision | | ruleTriggered | string? | Rule that triggered the decision, if any | | recommendedAction | string? | Recommended action for the integrator | | sessionSignature | string | Cryptographic signature for result verification |

Handle each decision type in your component:

import React from 'react';
import { View, Text, Button } from 'react-native';
import { UseSense, UseSenseResult } from 'react-native-usesense';

function VerificationScreen({ navigation }) {
  const handleVerify = async () => {
    try {
      const result: UseSenseResult = await UseSense.startSession({
        sessionType: 'enrollment',
      });

      switch (result.decision) {
        case 'approved':
          navigation.navigate('Home');
          break;
        case 'rejected':
          navigation.navigate('Retry', { reasons: result.reasons });
          break;
        case 'manual_review':
          navigation.navigate('PendingReview', { sessionId: result.sessionId });
          break;
      }
    } catch (error) {
      console.error('Session failed:', error.code);
    }
  };

  return (
    <View>
      <Button title="Verify Identity" onPress={handleVerify} />
    </View>
  );
}

Event Listening

Subscribe to real-time events during the verification lifecycle. Call addListener() before startSession() to receive all events.

import { UseSense, UseSenseEvent } from 'react-native-usesense';
import { useEffect, useState } from 'react';

function VerificationScreen() {
  const [events, setEvents] = useState<UseSenseEvent[]>([]);

  useEffect(() => {
    const listener = UseSense.addListener((event) => {
      setEvents(prev => [...prev, event]);

      switch (event.type) {
        case 'session_started':
          console.log('Session:', event.sessionId);
          break;
        case 'challenge_presented':
          console.log('Challenge:', event.challengeType);
          break;
        case 'challenge_completed':
          console.log('Challenge completed:', event.challengeType);
          break;
        case 'processing':
          console.log('Stage:', event.stage); // 'deepsense' | 'livesense' | 'matchsense' | 'fusion'
          break;
        case 'session_completed':
          console.log('Result:', event.result.decision);
          break;
        case 'session_error':
          console.error('Error:', event.error.code);
          break;
      }
    });

    return () => listener.remove();
  }, []);

  // render events...
}

Error Handling

All errors include a machine-readable code and a human-readable message.

| Code | Description | Recovery | |------|-------------|----------| | camera_permission_denied | Camera access not granted | Prompt user; link to device Settings via Linking.openSettings() | | microphone_permission_denied | Microphone not granted (audio enabled) | Prompt or disable audio | | session_timeout | Exceeded configured timeout | Retry with new session | | session_expired | 15-minute server-side expiry | Start new session | | network_error | API unreachable | Check connectivity, retry | | sdk_not_initialized | startSession() before initialize() | Call initialize() at app startup | | invalid_config | Missing or invalid config | Check apiKey and required fields | | invalid_api_key | Key rejected by server | Verify in dashboard; check environment | | insufficient_credits | Zero credit balance | Purchase credits in dashboard | | identity_not_found | identityId doesn't exist | Verify identity was enrolled | | camera_unavailable | No front camera found | Inform user | | device_not_supported | Fails hardware requirements | Inform user | | session_cancelled | Cancelled by user or programmatically | Handle gracefully | | play_integrity_unavailable | (Android) Play Integrity API unavailable | DeepSense uses fallback signals | | server_error | 5xx from UseSense API | Retry; contact support if persistent |

import { UseSense, UseSenseError } from 'react-native-usesense';
import { Alert, Linking } from 'react-native';

async function verify() {
  try {
    const result = await UseSense.startSession({ sessionType: 'enrollment' });
    // handle result
  } catch (error) {
    const err = error as UseSenseError;

    switch (err.code) {
      case 'camera_permission_denied':
        Alert.alert(
          'Camera Required',
          'UseSense needs camera access to verify your identity.',
          [
            { text: 'Cancel', style: 'cancel' },
            { text: 'Open Settings', onPress: () => Linking.openSettings() },
          ],
        );
        break;

      case 'session_timeout':
      case 'session_expired':
      case 'network_error':
        Alert.alert('Try Again', 'The session could not be completed. Please try again.');
        break;

      case 'insufficient_credits':
        console.error('UseSense credit balance is zero');
        Alert.alert('Service Unavailable', 'Verification is temporarily unavailable.');
        break;

      case 'session_cancelled':
        // User cancelled -- no action needed
        break;

      default:
        Alert.alert('Error', err.message);
        break;
    }
  }
}

Server-Side Webhook Verification

Never trust the SDK result for access-control decisions. The SDK response is for UI feedback only — showing the user a success or failure screen. The definitive verdict arrives at your backend via an HMAC-SHA256 signed webhook.

Webhook Payload

{
  "event": "session.completed",
  "session_id": "ses_abc123",
  "organization_id": "org_xyz",
  "timestamp": "2026-03-12T10:30:00Z",
  "data": {
    "decision": "approved",
    "channel_trust_score": 95,
    "liveness_score": 92,
    "matchsense_risk_score": 8,
    "presence_confidence": 94,
    "session_type": "enrollment",
    "identity_id": "idn_def456",
    "reasons": [],
    "rule_triggered": null,
    "session_signature": "sig_..."
  }
}

Signature Verification — Node.js (Express)

const crypto = require('crypto');

app.post('/webhooks/usesense', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-usesense-signature'];
  const timestamp = req.headers['x-usesense-timestamp'];

  const payload = `${timestamp}.${req.body}`;
  const expected = crypto
    .createHmac('sha256', process.env.USESENSE_WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);

  if (event.event === 'session.completed') {
    const { decision, session_id } = event.data;
    // Update your database based on the definitive decision
  }

  res.status(200).send('OK');
});

Signature Verification — Python (Flask)

import hmac
import hashlib

@app.route('/webhooks/usesense', methods=['POST'])
def usesense_webhook():
    signature = request.headers.get('X-UseSense-Signature')
    timestamp = request.headers.get('X-UseSense-Timestamp')

    payload = f"{timestamp}.{request.data.decode()}"
    expected = hmac.new(
        USESENSE_WEBHOOK_SECRET.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        return 'Invalid signature', 401

    event = request.get_json()

    if event['event'] == 'session.completed':
        decision = event['data']['decision']
        session_id = event['session_id']
        # Update your database based on the definitive decision

    return 'OK', 200

Signature Verification — Go (net/http)

func useSenseWebhook(w http.ResponseWriter, r *http.Request) {
    signature := r.Header.Get("X-UseSense-Signature")
    timestamp := r.Header.Get("X-UseSense-Timestamp")

    body, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "Bad request", http.StatusBadRequest)
        return
    }

    payload := fmt.Sprintf("%s.%s", timestamp, string(body))
    mac := hmac.New(sha256.New, []byte(os.Getenv("USESENSE_WEBHOOK_SECRET")))
    mac.Write([]byte(payload))
    expected := hex.EncodeToString(mac.Sum(nil))

    if !hmac.Equal([]byte(signature), []byte(expected)) {
        http.Error(w, "Invalid signature", http.StatusUnauthorized)
        return
    }

    var event map[string]interface{}
    json.Unmarshal(body, &event)

    // Process the event
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
}

Sandbox vs Production

| | Sandbox | Production | |---|---------|-----------| | Cost | Free, unlimited | Credit-based | | API keys | Separate | Separate | | Features | All features identical | All features identical | | Deduplication | Elevated risk scores (shared face collection) | Isolated per organization |

Switch by changing environment in config:

await UseSense.initialize({
  apiKey: process.env.USESENSE_API_KEY,
  environment: __DEV__ ? 'sandbox' : 'production',
});

Troubleshooting

| Problem | Solution | |---------|----------| | Module 'react-native-usesense' not found | Run pod install for iOS; rebuild for Android; verify auto-linking | | Camera permission denied on iOS | Add NSCameraUsageDescription to Info.plist | | Build fails on iOS with 'pod not found' | Run pod repo update then pod install | | Build fails on Android with dependency resolution error | Ensure mavenCentral() is in your project-level repositories | | Session always times out | Check network connectivity; increase timeout in config | | Deduplication always returns high risk on sandbox | Expected — sandbox uses a shared face collection | | Events not firing | Ensure addListener() is called before startSession() | | New Architecture errors | Ensure codegen ran: cd android && ./gradlew generateCodegenArtifactsFromSchema | | App crashes on Android with TransactionTooLargeException | Update to latest plugin version |

TypeScript Support

The plugin ships with full TypeScript declarations. All types are exported from the main entry point:

import {
  UseSense,
  UseSenseConfig,
  UseSenseResult,
  UseSenseError,
  UseSenseEvent,
  UseSenseDecision,
  UseSenseEnvironment,
  SessionType,
  ChallengePolicy,
  ProcessingStage,
  StartSessionOptions,
  SessionStatus,
  UseSenseSubscription,
} from 'react-native-usesense';

API Reference

UseSense.initialize(config: UseSenseConfig): Promise<void>

Initialize the plugin. Must be called once before any other method.

UseSense.startSession(options?: StartSessionOptions): Promise<UseSenseResult>

Start a verification session. Presents a full-screen native camera UI.

UseSense.cancelSession(): Promise<void>

Cancel an in-progress verification session.

UseSense.getSessionStatus(sessionId: string): Promise<SessionStatus>

Get the status of a verification session by ID.

UseSense.addListener(callback: (event: UseSenseEvent) => void): UseSenseSubscription

Subscribe to real-time events during the verification lifecycle.

UseSense.getSdkVersion(): string

Get the native SDK version string.

Changelog

See CHANGELOG.md.

License

Proprietary. See LICENSE file.

Support