How to build a barcode scanner with the Genius Scan SDK

As part of its structured data capabilities, the Genius Scan SDK is able to detect readable codes on documents. This enables you to get both a clean image of the document as well as structured data representing the readable codes present on the document. For instance, this may let you send a scanned document to the proper backend depending on a barcode present on the document.

We recommend using the Genius Scan SDK if you are building a barcode or qr-code scanning feature as part of a document acquisition process.

The following readable codes are supported:

  • aztec
  • code39
  • code93
  • code128
  • dataMatrix
  • ean8
  • ean13
  • itf
  • pdf417
  • qr
  • upce
  • codabar (Supported on iOS 15.0 and later)
  • gs1DataBar (Supported on iOS 15.0 and later)
  • microPDF417 (Supported on iOS 15.0 and later)
  • microQR (Supported on iOS 15.0 and later)
  • msiPlessey (Supported on iOS 17.0 and later)

In this guide, we will write a very simple barcode scanning app in a UIKit project. Writing this app should take about 10 minutes.

Getting started

Add the Genius Scan SDK as a dependency to your project by following the section Integrating the framework from the Getting Started guide.

Implement the receipt scanning scan flow

You will instantiate a scan flow with a specific configuration:

  • set configuration.structuredData to .readableCode to specify you are interested in scanning 2D-codes.
  • set configuration.struturedDataReadableCodeTypes to the readable codes you want to detect. By default, the SDK will attempt to detect any kind of supported code, but for better performane you should set this to only the code types you need.
  • set configuration.multiPage to false as generally you want the user to scan a single document and process it.
  • set skipPostProcessingScreen to true if you don’t need the user to review the document before processing it.
let configuration = GSKScanFlowConfiguration()
configuration.structuredData = .readableCode
configuration.structuredDataReadableCodeTypes = [.ean13]
configuration.multiPage = false
configuration.skipPostProcessingScreen =  true

Start the scan flow with the above configuration

You can now start the scan flow.

Note: The Genius Scan SDK offers multiple convenient ways of starting the scan flow, in particular from UIKit view controllers or from SwiftUI views.

// Keep a strong reference on ScanFlow
let scanFlow = GSKScanFlow(configuration: configuration)

do {
    let result = try await scanFlow.resultByStarting(fromViewController: viewController)
    handleResult(result)
} catch {
    handleError()
}

Handle the success

We can now write the handleResult method. Since this is a demo, we will just output the extracted data but in your real application you will likely display the data to the user for validation, and then serialize it to send it to your backend.

func handleResult(_ result: GSKScanFlowResult) {
    // We only consider the first scan since we are in single-page mode
    guard let scan = result.scans.first else {
        print("Unexpected error")
        return
    }

    // Check if there is structured data
    guard let structuredResult = scan.structuredDataResult else {
        print("No structured data result")
        return
    }

    // Check if a receipt has been detected
    guard let readableCodes = structuredResult.readableCodes else {
        print("No readable codes detected")
        return
    }

    for readableCode in readableCodes {
        print("Type: \(readableCode.type)")
        print("Value: \(readableCode.value)")
    }
}

Error handling

It’s important to handle the error as well, there are two important cases:

  • The scan flow is cancelled by the user. A special error is raised so that you can choose how to handle such situations. Maybe you don’t want to perform any action, but you can also show a message to the user.
  • The Genius Scan SDK license is expired. This could happen if your license isn’t renewed or if you don’t activate auto-refreshing of the license key. In this case, you may want to show a message or fall back to the regular camera depending on your needs.
func handleError(_ error: Error) {
    if (error as NSError).domain == GSKScanFlowErrorDomain && (error as NSError).code == GSKScanFlowError.userCancellation.rawValue {
        // Do nothing
    } else {
        // Show a UIAlertController with error.localizedDescription
    }
}

Launching the app

You can now build and run the application on an actual device (the iOS simulator doesn’t support the camera) to test the barcode scanning.

© 2025 The Grizzly Labs. All rights reserved.