# React Native

> On-device content moderation for React Native: check images, video, text and the live camera for unsafe content, with no cloud round-trip.

> For AI agents: the complete documentation index is at https://nosmai.com/llms/moderations.txt

Product: Nosmai Moderation
Group: platform-guides
Source: https://nosmai.com/docs/moderations/react-native/

## Install

```sh
npm install @nosmai/moderation-react-native@2.0.1
```

**iOS.** No extra step. The pod depends on `NosmaiModerationSDK`, so `pod install` pulls the native SDK and its encrypted models.

```sh
cd ios && pod install
```

Set the Podfile platform to `15.1`, and because the SDK is a static xcframework, keep `ENABLE_USER_SCRIPT_SANDBOXING = NO` (a Podfile `post_install` can force it). Add `NSCameraUsageDescription` and `ITSAppUsesNonExemptEncryption = NO` to `Info.plist`.

**Android.** The native SDK ships as a large AAR that the host app provides (the plugin references it at compile time only):

1. Download `nosmai-detection.aar` from the [Android releases](https://github.com/nosmai/moderation-sdk-android/releases) into `android/app/libs/nosmai-detection.aar`.
1. Reference it in `android/app/build.gradle`:

```gradle
android {
  defaultConfig {
    minSdkVersion 24
    ndk { abiFilters "arm64-v8a" }
  }
}
dependencies {
  implementation files("libs/nosmai-detection.aar")
}
```

3. Ensure the project uses Kotlin `2.2.0+`.

**Requirements:** React Native with the New Architecture (TurboModules) enabled, Android `minSdk 24` (arm64-v8a), iOS 15.1+.

> [!NOTE]
Distribute Android as an App Bundle (AAB). The SDK ships `arm64-v8a` only, so Play hides it from 32-bit-only devices, and it does not run on x86_64 emulators.

## Initialize

Call once at startup with your license key, loading only the models you need. It runs natively on a background thread.

```tsx
import { NosmaiModeration } from '@nosmai/moderation-react-native';

const res = await NosmaiModeration.initialize('NOSMAI-XXXX', ['nsfw']);
if (!res.success) {
  console.warn('Nosmai init failed:', res.error);
}
```

## Moderate an image

Pass a local file path (for example from `react-native-image-picker`). Returns a `NosmaiResult`.

```tsx
const r = await NosmaiModeration.analyzeImage(filePath);
if (r.isUnsafe) {
  // r.nsfw -> 'safe' | 'warn' | 'block'
  console.log('nsfw:', r.nsfw);
}
```

No lifecycle code is required for image analysis. If the app was backgrounded,
the visual model reloads automatically on the next call.

## Moderate a video

Samples one frame every `frameIntervalMs` and aggregates.

```tsx
const v = await NosmaiModeration.analyzeVideo(filePath, 500);
if (v.isUnsafe) {
  console.log('categories:', v.categories, 'frames:', v.framesAnalyzed);
}
```

Existing image and recorded-video integrations do not need API changes when
upgrading to `2.0.1`.

## Moderate text

Load the text model once (it is larger) after `initialize`, then moderate messages.

```tsx
await NosmaiModeration.initializeText();            // after initialize()

const t = await NosmaiModeration.moderateText('some message');
if (t.blocked) {
  // t.layer -> 'blocklist' | 'classifier', t.category, t.matchedWord
  console.log('blocked:', t.category, t.layer, t.matchedWord);
}
```

## Live camera

The camera, frame capture and detection all run natively. Render `<NosmaiCameraPreview />` to open the camera and stream per-frame results: mounting starts it, unmounting stops it. Only the per-frame `NosmaiResult` crosses into JS.

```tsx
import { NosmaiCameraPreview } from '@nosmai/moderation-react-native';
import { useIsFocused } from '@react-navigation/native';

const isFocused = useIsFocused();

<NosmaiCameraPreview
  style={{ flex: 1 }}
  facing="back"                 // or "front"
  active={isFocused}
  onResult={(r) => setVerdict(r.isUnsafe ? 'UNSAFE' : 'SAFE')}
/>;
```

> [!NOTE]
Request the camera permission before mounting the preview (`PermissionsAndroid` on Android; the `NSCameraUsageDescription` prompt on iOS).

App backgrounding is handled automatically: camera and visual-model resources
are suspended, then restored when the app becomes active. Use `active={false}`
when navigation keeps a hidden camera screen mounted. If the screen unmounts
normally, the `active` prop is optional.

## Thresholds

Adjust the NSFW bars at runtime (lower is stricter).

```tsx
NosmaiModeration.setNsfwThreshold('explicit', 0.45); // BLOCK
NosmaiModeration.setNsfwThreshold('sexy', 0.55);     // WARN
```

## Cleanup

```tsx
NosmaiModeration.shutdown();
```

> [!NOTE]
`initialize`, `analyzeImage`, `analyzeVideo`, `moderateText` and `initializeText` are async. They run native inference off the JS thread, so the UI never blocks. Type enums (`NosmaiModel`, `NosmaiNsfwVerdict`, ...) are plain strings, matching the iOS, Android and web SDKs.
