Actual Capture Paper Receipts: iOS Developer Guide

This guide covers everything you need to integrate paper receipt scanning into your iOS app: how it works, setup, camera options, correction flows, and references.

How It Works

  1. Capture — The user photographs a receipt using the device camera.
  2. Extract — OCR processes the image on-device and returns structured data: merchant, date, total, line items, payment method, and more.
  3. Enrich (optional) — If Product Intelligence is enabled, extracted line items are matched against the product catalog for UPC, brand, category, and normalized product names.

All processing happens on-device. No receipt images are sent to the cloud.

Installation

CocoaPods:

pod 'BlinkReceipt'

Swift Package Manager:

https://github.com/BlinkReceipt/blinkreceipt-ios

Prerequisites: Xcode 12+, iOS 11.0+ deployment target, camera permissions.

 iOS SDK Repository (GitHub)

License Configuration

Set your license key in the AppDelegate at app launch:

Objective-C:

#import <BlinkReceipt/BlinkReceipt.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [BRScanManager sharedManager].licenseKey = @"YOUR-LICENSE-KEY";
    return YES;
}

Swift:

import BlinkReceipt

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    BRScanManager.shared().licenseKey = "YOUR-LICENSE-KEY"
    return true
}

Add camera permissions to your Info.plist:

<key>NSCameraUsageDescription</key>
<string>This app uses the camera to scan receipts</string>

Camera Options

Option A: Out-of-the-Box Camera (Standard)

The fastest path. The SDK provides a complete camera interface with alignment guidance, blur detection, and real-time feedback.

- (IBAction)btnTouched:(id)sender {
    BRScanOptions *scanOptions = [BRScanOptions new];

    [[BRScanManager sharedManager] startStaticCameraFromController:self
                                                        cameraType:BRCameraUXStandard
                                                       scanOptions:scanOptions
                                                      withDelegate:self];
}

Implement the delegate callback:

@interface MyViewController () <BRScanResultsDelegate>

- (void)didFinishScanning:(UIViewController *)cameraViewController
          withScanResults:(BRScanResults *)scanResults {
    [cameraViewController dismissViewControllerAnimated:YES completion:nil];
    // Use scan results
}

Configurable scan options:

OptionWhat it does
enableAutoCaptureAutomatically captures when receipt is properly positioned
enableTorchEnables flash control
enablePhotoGalleryAllows scanning from photo library
detectDuplicatesChecks for duplicate receipts and fraud
returnVoidedProductsReturns voided products with isVoided flag
countryCodeISO 2-character country code for the receipts being scanned

→ BRScanOptions Reference

Option B: Enhanced Camera UX

Same setup as Option A, but specify BRCameraUXEnhanced for improved graphics, messaging, and animations:

[[BRScanManager sharedManager] startStaticCameraFromController:self
                                                    cameraType:BRCameraUXEnhanced
                                                   scanOptions:scanOptions
                                                  withDelegate:self];

Data Chips: Enable on-screen indicators that show the user when key fields are detected:

scanOptions.enableDateChip = YES;
scanOptions.enableTotalChip = YES;
scanOptions.enableMerchantChip = YES;

Note: Some merchant detection methods only run at the end of the scan session. The merchant chip may not appear during scanning but the merchant will still be returned in the results.

→ Enhanced Camera UX Guide

Option C: Custom Camera Controller

Build your own UI on top of the SDK’s scanning engine.

Step 1: Subclass BRCameraViewController:

#import <BlinkReceipt/BlinkReceipt.h>

@interface MyCameraController : BRCameraViewController

Step 2: Set background to transparent:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor clearColor];
}

Step 3: Set the scanning region (values are percentages, 0.0 to 1.0):

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.scanningRegion = CGRectMake(0.1, 0.05, 0.8, 0.65);
}

Step 4: Wire your UI to the base class methods:

MethodWhen to call
userSnappedPhotoOnReady:User taps the capture button
userConfirmedFrame:User accepts the captured image
userFinishedScanUser indicates the scan is complete
userCancelledScanUser cancels the session

Step 5: Launch your custom controller:

MyCameraController *cameraController = [MyCameraController new];

[[BRScanManager sharedManager] startCustomCamera:cameraController
                                  fromController:self
                                     scanOptions:scanOptions
                                    withDelegate:self];

→ Custom Camera Controller Guide → BRCameraViewController Reference

Long Receipts

For receipts that don’t fit in a single frame, the SDK supports multi-frame capture:

  1. The user captures the first section of the receipt normally.
  2. After the first capture, the bottom edge of the previous frame appears at the top of the screen as an alignment guide.
  3. The user positions the next section with slight overlap and captures again.
  4. Repeat until the entire receipt is captured.
  5. The SDK stitches all frames together and returns a single set of results.

The out-of-the-box and enhanced cameras handle this flow automatically. If using a custom camera controller, you are responsible for displaying alignment cues and managing the multi-frame flow through the base class methods.

Receipt Correction

An optional flow that lets users review and edit extracted data after scanning. Especially useful for promotion validation workflows.

Stock Correction UI

[[BRScanManager sharedManager] startReceiptCorrection:@"BLINK-RECEIPT-ID"
                                   fromViewController:self
                                       withCustomFont:nil
                                       withCompletion:^(BRScanResults *results, NSError *error) {
    [self dismissViewControllerAnimated:YES completion:nil];
    // Use corrected results
}];

You can pass a custom UIFont to style the correction UI. Font size is ignored; the font family is applied.

To enable correction of historical receipts:

[BRScanManager sharedManager].daysToStoreReceiptData = 30; // Default is 0 (no local storage)

Custom Correction UI

Step 1: Load receipt data:

[[BRScanManager sharedManager] getResultsForReceiptCorrection:@"BLINK-RECEIPT-ID"
                                               withCompletion:^(BRScanResults *results, NSArray<UIImage *> *images) {
    // Display your own UI
}];

Step 2: Modify products:

[product userCorrectedBrand:@"Kraft"
                        upc:@"12345678901"
                productName:@"Macaroni & Cheese"
                   imageUrl:@"https://example.com/image.png"
                 totalPrice:2.99
                   quantity:1.0];

Step 3: Submit for validation:

[[BRScanManager sharedManager] submitUpdatedResultsForValidation:scanResults
                                                 withCountryCode:nil
                                                  withCompletion:^(BRScanResults *results, NSError *error) {
    // Results include updated qualifiedPromotions
}];

Fields in corrected results:

  • userAdded — Product was added by the user during correction
  • userModified — One or more properties were changed during correction

→ Receipt Correction Guide

Localization

[BRScanManager sharedManager].preferredLanguage = @"es"; // Spanish

Available: en, es, fr, de, it, pt, nl, sv, da, no, fi.

 Localization Guide

Receipt Quality & Feedback

FieldWhat it tells you
is_receiptWhether the image appears to be a valid receipt
is_blurryWhether the image is too blurry to extract reliably
is_screenWhether the image appears to be a photo of a screen
is_fraudulentWhether the receipt appears manipulated or counterfeit (US only, select banners)
is_duplicateWhether this receipt has been submitted before (2-week window, within your instance)
ocr_confidenceAverage OCR confidence score across all characters

Debug Mode

[BRScanManager sharedManager].debugMode = YES;

Testing Recommendations

  • Test with various receipt types: thermal, inkjet, laser-printed
  • Test in different lighting conditions: bright, dim, mixed
  • Test with challenging receipts: crumpled, faded, long, torn
  • Test across device types: older phones, budget devices, different screen sizes

Implementation Timeline

ScopeEstimated Dev Time
Out-of-the-Box Camera~1 week + QA
Custom Camera~2 weeks + QA

Key Classes & References

ClassWhat it does
BRScanManagerMain SDK manager — license, scanning, correction
BRScanOptionsConfiguration options for scanning sessions
BRScanResultsScan results including trip and basket data
BRProductIndividual product from a receipt
BRCameraViewControllerBase class for custom camera controllers
BRScanResultsDelegateProtocol for receiving scan results
BRErrorCodesError codes

Related

Let’s Turn Proof Into Action 

Your next move should be backed by proof, and we’re here to help you leverage real data for real results. Start turning verified insights into measurable impact today.