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

@authenta/react-native

v1.0.9

Published

Authenta React Native SDK — camera capture UI powered by @authenta/core

Readme

@authenta/react-native

React Native UI for the Authenta platform. Wraps @authenta/core in a self-contained modal — your app sets four toggles and receives the result.

One import, one component, one client:

import { AuthentaCapture, AuthentaClient } from '@authenta/react-native';

| Toggle | What the modal does | |---|---| | livenessCheck · faceswapCheck · faceSimilarityCheck | Opens the camera, captures, uploads, polls, returns the verdict | | faceIndexing | Switches to enrol/search — index a person's photos, or match a face |

The two features are mutually exclusive; asking for both raises a ValidationError.


Table of Contents


Requirements

| Dependency | Version | |---|---| | React Native | ≥ 0.72 | | React | ≥ 18 | | react-native-vision-camera | ≥ 5 | | react-native-image-picker | ≥ 7 | | react-native-blob-util | ≥ 0.19 | | react-native-compressor | ≥ 1.18 | | react-native-nitro-modules | ≥ 0.35 | | react-native-nitro-image | ≥ 0.14 | | @bam.tech/react-native-image-resizer | ≥ 3.0 |


Installation

npm install @authenta/react-native

npm install react-native-vision-camera react-native-image-picker \
  react-native-blob-util react-native-compressor \
  react-native-nitro-modules react-native-nitro-image \
  @bam.tech/react-native-image-resizer

Then link the native modules:

# iOS
cd ios && pod install && cd ..
npx react-native run-ios

# Android
npx react-native run-android

Android Setup

Add to android/app/src/main/AndroidManifest.xml inside <manifest>:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

No microphone permission is needed — video is recorded without audio, so the SDK never requests it.


iOS Setup

Add to ios/<AppName>/Info.plist:

<key>NSCameraUsageDescription</key>
<string>Camera is required for face capture during identity verification.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is required to select images for face indexing.</string>

Quick Start

import React, { useState } from 'react';
import { Button, View } from 'react-native';
import { AuthentaCapture, AuthentaClient } from '@authenta/react-native';

// Create once — outside your component, or in a context/singleton
const client = new AuthentaClient({
  baseUrl:      'https://platform.authenta.ai',
  api_key:      'YOUR_API_KEY',
  auth_enabled: true,
});

export default function App() {
  const [open, setOpen] = useState(false);

  return (
    <View>
      <Button title="Start Verification" onPress={() => setOpen(true)} />

      <AuthentaCapture
        client={client}
        visible={open}
        onClose={() => setOpen(false)}

        livenessCheck={true}
        faceswapCheck={false}
        faceSimilarityCheck={false}
        faceIndexing={false}

        onResult={(media) => {
          setOpen(false);
          console.log(media.result?.isSpoof);
        }}
        onError={(err) => console.error(err.message)}
      />
    </View>
  );
}

Props

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | client | AuthentaClient | Yes | — | One client serves both features | | visible | boolean | Yes | — | Controls modal open/close | | onClose | () => void | Yes | — | Called when the user dismisses the modal | | livenessCheck | boolean | No | false | Run the liveness check | | faceswapCheck | boolean | No | false | Run the faceswap check (video) | | faceSimilarityCheck | boolean | No | false | Run the similarity check (needs referenceImage) | | faceIndexing | boolean | No | false | Switch to enrol/search instead of detection | | referenceImage | string | No | — | Reference photo URI for faceSimilarityCheck | | modelType | ModelType | No | 'FI-1' | Detection model to run | | maxImages | number | No | 3 | How many photos may be indexed at once | | onResult | (result: ProcessedMedia) => void | No | — | Detection finished | | onEnrolled | (result: EnrollResponse) => void | No | — | Photos uploaded for indexing | | onSearchResult | (result: SearchResponse) => void | No | — | Face search returned matches | | onError | (error: Error) => void | No | — | Validation, capture, or API error |

Enforced on open, surfacing through onError as a ValidationError:

  • faceIndexing with any detection check — face indexing runs no model
  • No check enabled at all for FI-1
  • faceswapCheck together with faceSimilarityCheck — one needs video, the other a photo

Detection

busy → camera → analysing → result

The host app already chose the checks, so the modal asks the user nothing. It takes camera permission, opens the camera in the right mode, uploads what was captured, polls, and shows the verdict.

Capture rules

| Checks enabled | Capture mode | Notes | |---|---|---| | livenessCheck only | Photo and video — user chooses | Both buttons shown | | faceswapCheck only | Video only (max 10 s) | | | faceSimilarityCheck only | Photo only | Supply referenceImage | | faceswapCheck + livenessCheck | Video only | faceswap takes priority | | livenessCheck + faceSimilarityCheck | Photo only | similarity takes priority | | faceswapCheck + faceSimilarityCheck | — | Not allowed |

The user can flip between front and back camera except while recording. Video is capped at 10 seconds and 7 MB, and compressed before upload if it exceeds 6 MB. Recording never captures audio.

Result object

onResult receives a ProcessedMedia:

{
  id:         string;        // job ID
  tenantId:   string;
  taskTypeId: string;        // e.g. "8" for FI-1
  status:     string;        // "completed"
  cost:       number;
  createdAt:  string;
  updatedAt:  string;
  result: {
    isSpoof?:         boolean | string;  // liveness
    isDeepFake?:      boolean | string;  // faceswap
    isSimilar?:       boolean | string;  // similarity
    similarityScore?: number  | string;
  } | null;
  artifacts: Artifact[];
  taskType:  TaskType;
}

Face Indexing

Set faceIndexing and the same component becomes an indexing tool. Enrolling and searching are independent — searching needs no prior enrolment in this session, since it matches everything already indexed on the account.

Flow

              ┌─────────────────────────┐
              │     Face Indexing       │
              │  [Index a Face]         │
              │  [Search a Face]        │
              └──────┬───────────┬──────┘
                     │           │
        ┌────────────┘           └────────────┐
        ▼                                     ▼
  Add photos                            Pick a photo
  camera or library                     camera or library
        ▼                                     ▼
  Uploading…                            Matching…
        ▼                                     ▼
  ┌──────────────┐                    ┌──────────────────┐
  │ Faces Indexed│                    │ Search Results   │
  │ [Index More] │                    │ ranked matches   │
  │ [Search]     │                    │ [Search Another] │
  │ [Done]       │                    │ [Back]           │
  └──────────────┘                    └──────────────────┘

Both halves take photos from the camera or the library. HEIC from the iOS library is converted to JPEG automatically for enrolment, since the server accepts only JPEG, PNG, and WebP.

Search photos are downscaled before upload, then posted as multipart/form-data. The ladder tries 560 → 480 → 400 → 320 px and stops at the first result under 74,000 bytes, so a full-resolution camera photo never goes over the wire.

Size costs nothing here: measured against the live API, every size from 560 px down to 160 px returned the same top match within a 1.8-point band (0.8797–0.8974). The embedding model crops to 112×112 internally, so extra pixels buy nothing.

What does matter is that the resize bakes EXIF rotation into the pixels. An image left with a bogus orientation tag is read sideways by face detection and comes back as no_face_detected.

The modal stays open after each step so the user can keep going. Close it from onClose when you would rather show results in your own UI.

Results

onEnrolled receives an EnrollResponse — the photos are uploaded, but embeddings are generated in the background:

{
  subject_id: string;
  status:     string;
  faces:      Array<{ face_id: string; status: string }>;
  expires_at: string;
}

Call client.tenants() afterwards to watch each face reach processed.

onSearchResult receives a SearchResponse, strongest match first:

{
  count: number;
  results: Array<{
    rank: number; subject_id: string; face_id: string;
    name: string; image_url: string; similarity_score: number;   // 0–1
  }>;
}

Using AuthentaClient Directly

@authenta/react-native re-exports all of @authenta/core, so one import is enough. Use the client headless if you have your own UI.

import { AuthentaClient } from '@authenta/react-native';

const client = new AuthentaClient({
  baseUrl: 'https://platform.authenta.ai',
  api_key: 'YOUR_API_KEY',
  auth_enabled: true,
});

const media   = await client.uploadAndPoll('file:///selfie.jpg', 'FI-1', { livenessCheck: true });
const subject = await client.faceEnrol([{ uri: 'file:///front.jpg' }]);
const matches = await client.faceSearch('file:///query.jpg', { limit: 10 });
const all     = await client.tenants();

See the @authenta/core README for the full API reference.


Error Handling

Everything reaches onError, and every error extends AuthentaError.

import {
  AuthentaError,
  AuthenticationError,
  AuthorizationError,
  QuotaExceededError,
  InsufficientCreditsError,
  ValidationError,
  ServerError,
} from '@authenta/react-native';

if (err instanceof AuthenticationError) {
  // Invalid api_key — code: "IAM001"
} else if (err instanceof ValidationError) {
  // Bad toggle combination or unsupported image
} else if (err instanceof AuthentaError) {
  console.error(err.message, err.code, err.statusCode, err.details);
}

Camera errors

Surfaced through onError with a human-readable message:

| Situation | Message | |---|---| | Active phone call | "The camera was interrupted by a phone call. End the call and tap Try Again." | | Active video call (FaceTime / Zoom) | "The camera is in use by another app. Please end that call and try again." | | Camera not ready yet | "Camera is still starting. Please try again in a moment." | | Recording failed | "Recording failed" |

Detection allows up to 3 retry attempts before the user must dismiss and restart.


Platform Notes

iOS

  • Each capture starts a fresh native AVCaptureSession, preventing a crash that occurs when a session is reused after an error or interruption. Android's Camera2 API has no such restriction.
  • Audio phone calls: photo capture works normally. Video recording is unavailable while iOS holds the audio session.
  • Video calls (FaceTime, Zoom, Teams): the active call app gets exclusive camera access — the user must end the call first.
  • Screen recording / mirroring: neither blocks the camera.

Android

  • Camera permission is requested at runtime on first use.
  • No known restrictions alongside audio calls.

TypeScript Types

The component's props plus every @authenta/core type:

import type {
  AuthentaCaptureProps,

  // Detection
  AuthentaClientConfig,
  ModelType,
  RunOptions,
  ProcessedMedia,
  DetectionResult,

  // Face indexing
  LocalFaceImage,
  EnrollResponse,
  TenantResponse,
  TenantFace,
  SearchResponse,
  SearchMatch,
  FaceStatus,
} from '@authenta/react-native';

License

MIT © Authenta