Install
npm install @nosmai/moderation-react-native
iOS. No extra step. The pod depends on NosmaiModerationSDK, so pod install pulls the native SDK and its encrypted models.
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):
- Download
nosmai-detection.aarfrom the Android releases intoandroid/app/libs/nosmai-detection.aar. - Reference it in
android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 24
ndk { abiFilters "arm64-v8a" }
}
}
dependencies {
implementation files("libs/nosmai-detection.aar")
}
- 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-v8aonly, 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.
import { NosmaiModeration } from '@nosmai/moderation-react-native';
const res = await NosmaiModeration.initialize('NOSMAI-XXXX', ['objectDetection', '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.
const r = await NosmaiModeration.analyzeImage(filePath);
if (r.isUnsafe) {
// r.detections -> [{ category, confidence }], r.nsfw -> 'safe' | 'warn' | 'block'
r.detections.forEach((d) =>
console.log(d.category, `${Math.round(d.confidence * 100)}%`),
);
}
Moderate a video
Samples one frame every frameIntervalMs and aggregates.
const v = await NosmaiModeration.analyzeVideo(filePath, 500);
if (v.isUnsafe) {
console.log('categories:', v.categories, 'frames:', v.framesAnalyzed);
}
Moderate text
Load the text model once (it is larger) after initialize, then moderate messages.
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.
import { NosmaiCameraPreview } from '@nosmai/moderation-react-native';
<NosmaiCameraPreview
style={{ flex: 1 }}
facing="back" // or "front"
onResult={(r) => setVerdict(r.isUnsafe ? 'UNSAFE' : 'SAFE')}
/>;
[!NOTE] Request the camera permission before mounting the preview (
PermissionsAndroidon Android; theNSCameraUsageDescriptionprompt on iOS).
Thresholds
Adjust any object class or NSFW bar at runtime (lower is stricter).
NosmaiModeration.setThreshold('weapon', 0.7);
NosmaiModeration.setNsfwThreshold('explicit', 0.45); // BLOCK
NosmaiModeration.setNsfwThreshold('sexy', 0.55); // WARN
Cleanup
NosmaiModeration.shutdown();
[!NOTE]
initialize,analyzeImage,analyzeVideo,moderateTextandinitializeTextare async. They run native inference off the JS thread, so the UI never blocks. Type enums (NosmaiModel,NosmaiCategory,NosmaiNsfwVerdict, ...) are plain strings, matching the iOS, Android and web SDKs.