DragonflAI SDK for iOS



DragonflAI is a commercial product and requires licensing details during framework initialization. This should have been provided alongside this documentation, but if not please contact

Initialise early in your app’s startup. For example here in the AppDelegate method application:willFinishLaunchingWithOptions:, we call useAccount() with our license details.

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // To see debug log messages, pass a debug logger.
        // NB: limit use to debug builds 
        DragonflAICore.useLogger(logger: ConsoleLogger(logLevel: .debug))
        let account = Account(key: "your_key", secret: "your_secret")        
        return true

This is a basic example. You may wish to keep your credentials in config rather than code.

Moderating an image

Create a Moderator instance, and pass an image to moderate().

Basic example using a closure to handle the result:
let image: UIImage = [your choice of image]

Moderator(algorithm: .nudity1).moderate(image) { (moderationResult) in
    // *** update model in background thread ***

    // *** example of expanding result ***
    switch moderationResult {
    case .success(let success):
        switch success.analysis.decision {
        case .ok:
            // moderator allowed this image
        case .blocked:
            // moderator blocked this image
        @unknown default:
            // this covers any future return types 
    case .failure(let error):
        // moderation error
    DispatchQueue.main.async {
        // *** update UI in main thread ***

⚠️ You should assume the closure is not called on the main queue, and dispatch UI updates accordingly.

Configuring a moderator

You may want to configure and reuse a Moderator instance instead of creating it every time.

It can take an optional AlgorithmConfig object if you don’t want to use the defaults.

let config = AlgorithmConfig(blockThreshold: 50)
let moderator = Moderator(algorithm: .nudity1, config: config)

// ...

moderator.moderate(image) { (moderationResult) in 
    // use result
Promises (PromiseKit)

You can also get the results via PromiseKit promises.

    .map { (success: ModeratorSuccess) in
        // use analysis and metadata
    .catch { error in
        // handle error

Moderating a video stream

Streams of images can also be moderated in v1.4+. Typically these come from the device cameras and are passed to a codec for streaming or real-time communication.

Creating a StreamModerator

Get a StreamModerator by asking a Moderator to createStreamModerator()

class MyClass {
    private var streamModerator: StreamModerator?

    init() {
        let moderator = Moderator(algorithm: .nudity1)
        streamModerator = moderator.createStreamModerator()
        streamModerator?.delegate = self    
Supplying stream frames

Pass the frames, e.g. from the camera, to the process(frame:) method.

extension MyClass: AVCaptureVideoDataOutputSampleBufferDelegate {    
  func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {

    let pixelBuffer: CVPixelBuffer? = CMSampleBufferGetImageBuffer(sampleBuffer)

    guard let pixelBuffer = pixelBuffer else {

    streamModerator?.process(frame: pixelBuffer)

    // pass pixelBuffer to codec (dependent on moderation result) 

Getting results

To get results, assign a delegate, typically the same class.

extension MyClass: StreamModeratorDelegate {
    func moderatorDidProduceNewResult(_ moderator: StreamModerator,
                                      result moderationResult: ModeratorResult) {
        guard moderator == self.streamModerator else {

        // use moderationResult

    func moderatorDidDropFrame(_ moderator: StreamModerator) {
        // dropped frame
Getting stream statistics

The StreamModerator can provide statistics on the number of frames it is receiving and processing.

func printStats() {
    print("Input FPS: \(streamModerator.inputFramesPerSecond) / Processed FPS: \(moderator.processedFramesPerSecond)")

For consistent results, reset those stats when starting or resuming a session, so periods with no frames are not included.

func startVideoSession() {
    // ...


    // ...