# iOS

> Use Nosmai Moderation in a native iOS (Swift) app: image, video, text and live-camera moderation.

> 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/ios/

## Install

Install via CocoaPods. Add the pod to your `Podfile` and run `pod install`. The SDK and its bundled models come with the pod, and everything runs on-device with no external dependencies.

```ruby
pod 'NosmaiModerationSDK', '~> 2.0.1'
```

**Requirements:** iOS 15.1+, arm64. In `Info.plist` add:

- `NSCameraUsageDescription`, required for the live-camera path.
- `ITSAppUsesNonExemptEncryption` set to `NO`. The SDK only encrypts its own bundled models locally, which is export-compliance exempt. Without this, every TestFlight or App Store upload stalls on the encryption question.

## Initialize

`initialize` is blocking (network plus model load), so call it off the main thread. It returns `false` if the license is invalid or expired.

```swift
import NosmaiDetection

DispatchQueue.global(qos: .userInitiated).async {
    let ok = NosmaiSDK.initialize(licenseKey: "NOSMAI-XXXX")
}
```

## Moderate an image

```swift
if let r = NosmaiSDK.analyzeImage(uiImage) {     // NosmaiResult?
    if r.isUnsafe {
        // r.nsfw -> .safe / .warn / .block
    }
}
```

## Moderate a video

```swift
NosmaiSDK.analyze(videoURL: url, frameIntervalMs: 500,
    progress: { p in /* 0...1 */ },
    completion: { result in /* result.isUnsafe, .categories, .flags */ })
```

## Moderate text

Call `initialize` first, since it validates the license. `initializeText` needs that before it can load the text model.

```swift
try? NosmaiSDK.initializeText()                  // after initialize(), off the main thread
if let t = NosmaiSDK.moderateText("some message") {
    if t.blocked { /* t.layer, t.category, t.matchedWord */ }
}
```

## Live camera (AVCaptureSession)

Feed pixel buffers from your `AVCaptureVideoDataOutput` to `pushFrame`. Results arrive via the `NosmaiListener`.

```swift
NosmaiSDK.startStream(listener: self)            // self conforms to NosmaiListener

// in captureOutput(_:didOutput:from:)
if let pb = CMSampleBufferGetImageBuffer(sampleBuffer) {
    NosmaiSDK.pushFrame(pb, rotationDegrees: 90)  // 90 makes a back-camera portrait buffer upright
}

// on leave
NosmaiSDK.stopStream()
```

Show the preview with an `AVCaptureVideoPreviewLayer` backed by the same `AVCaptureSession`.

## App and screen lifecycle

App backgrounding is handled automatically. The SDK stops live moderation and
releases its visual model resources. The next `startStream`, `analyzeImage` or
`analyzeVideo` call reloads them automatically.

When the app remains active but the moderation screen is closed or hidden,
suspend its visual resources explicitly:

```swift
NosmaiSDK.suspendVisualModeration()
```

Stop your `AVCaptureSession` at the same time. Text moderation remains ready and
does not need to be initialized again.

## Thresholds

```swift
NosmaiSDK.setNsfwThreshold(.explicit, value: 0.45)  // BLOCK
NosmaiSDK.setNsfwThreshold(.sexy, value: 0.55)      // WARN
```

## Cleanup

```swift
NosmaiSDK.shutdown()
```

> [!NOTE]
`analyzeImage` and `moderateText` are synchronous and fast, but they still run inference, so call them off the main thread. `analyzeVideo` is async with a completion handler.
