SDK reference · iOS SDK / iOS Individual Modules

NFC

The NFC module reads the secure NFC chip embedded in ICAO 9303-compliant travel documents, such as e-passports. It then returns the document holder's data, including the chip's portrait image. When a flow captures multiple IDs, NFC Scan applies only to the first ID. Chip reading uses secure messaging; see Security.

For an overview of this module and how it works, see NFC Scan.

This page covers the code-configured flow: building an IncdOnboardingFlowConfiguration in your app and calling startOnboarding. When the flow is defined in Dashboard instead and started with startFlow or startWorkflow, the NFC step is configured server-side. See Integration Approaches.

This module requires the NFCReaderUsageDescription key and the ISO 7816 application identifiers. See Add Required Permissions.

Availability: The -nfc build variant, on NFC-capable devices running iOS 13 or later. Calling it from a non-NFC variant triggers a runtime variant assertion (IncdOnboardingVariant.assertIncludes(.nfc)).

UI: standalone (Apple's system NFC sheet).

Use this module when:

  • You need a high-assurance read of the document chip, not just an OCR of the printed page.
  • Your flow performs .nfcSelfie or .nfc3Way Face Match against the chip photo. These match types become available when processNFCData is enabled.

Add NFC

  1. Build the SDK with the -nfc variant so the NFC module is linked in.
  2. Add ID Capture (addIdScan(scanStep: .both)) then Process ID (addIdProcess()), before NFC. NFC reads the chip after the document has been captured and processed.
  3. Add the module with addNfcScan(). All parameters are optional; omitting one falls back to its default.
    flowConfig.addNfcScan(
        idType: nil,                              // .id or .passport; nil uses the captured/selected type
        showNFCSymbolConfirmationScreen: nil,     // ask the user to confirm the chip symbol (default true)
        showInitialDataConfirmationScreen: nil,   // confirm the key data before reading (default true)
        showTutorials: nil,                       // show scanning tutorials (default true)
        nfcMaxRetries: nil,                        // retry budget (default 5)
        processNFCData: nil,                       // process the read data on the backend (default true)
        returnResultImmediately: nil               // return as soon as the chip is read (default false)
    )
    

Example

The example below adds NFC after ID Capture and ID OCR/Process, shows the NFC symbol confirmation screen, processes the chip data, and listens for the result through the onNFCScanCompleted(_:) delegate callback.

let flow = IncdOnboardingFlowConfiguration()
flow.addIdScan(scanStep: .both)
// ID OCR runs automatically after a .both ID Capture
flow.addNfcScan(
    showNFCSymbolConfirmationScreen: true,
    processNFCData: true
)

IncdOnboardingManager.shared.startOnboarding(
    sessionConfig: IncdOnboardingSessionConfiguration(token: "<SESSION_TOKEN>"),
    flowConfig: flow,
    delegate: self
)
extension MyViewController: IncdOnboardingDelegate {
    func onNFCScanCompleted(_ result: NFCScanResult) {
        // NFC scan completed. Process the result.
    }
}

Configuration Options

Configure the module with addNfcScan().

Option Type Description
idType IdType? .id or .passport; nil uses the document already captured or selected.
showNFCSymbolConfirmationScreen Bool? Shows a screen asking whether the document contains an NFC chip. Default: true.
showInitialDataConfirmationScreen Bool? Confirms the key data before reading the chip. Default: true.
showTutorials Bool? Shows tutorials on how to scan the document. Default: true.
nfcMaxRetries Int? Sets the maximum number of NFC scan attempts. Default: 5.
processNFCData Bool? Submits the chip data to the back end for identity validation. Enables the .nfcSelfie and .nfc3Way Face Match types. Default: true.
returnResultImmediately Bool? Returns as soon as the chip is read. Default: false.

For each NFC read, the SDK tries the PACE protocol first and falls back to BAC when PACE is unavailable or fails. PACE and BAC are alternatives, not both required. An NFC chip whose access protocol the device cannot complete fails the scan and routes through the retries configured using nfcMaxRetries.

Result

func onNFCScanCompleted(_ result: NFCScanResult)

NFCScanResult fields:

  • facePhoto: UIImage?: The document holder's face image decoded from the chip.
  • dg1: NFCDataModel.DG1?: The machine-readable zone (MRZ) data (DG1). Its fields include:
    • documentNumber: The nine most-significant digits of the document number.
    • documentCode: The MRZ document code. One of the following: TD1, TD2, TD3, MRVA, or MRVB. The default is TD3.
    • nationality: The document holder's nationality as a three-letter code.
    • issuingStateOrOrganization: The issuing state or organization as a three-letter code.
    • birthDate: The date of birth in yyMMdd format (DG1).
    • expireAt: The document expiry date in yyMMdd format (DG1).
    • gender: The document holder's gender. One of the following: MALE, FEMALE, UNKNOWN, or UNSPECIFIED.
    • primaryIdentifier: The document holder's last name.
    • secondaryIdentifier: The document holder's first name.
    • optionalData1: First optional data field (ID-1 and ID-3 style MRZs).
    • optionalData2: Second optional data field (ID-1 style MRZs only); may be null.
    • personalNumber: Personal number, if encoded in optionalData1.
    • The corresponding MRZ check-digit fields:
      • compositeCheckDigit: The MRZ composite check digit (DG1); < when unset.
      • dateOfBirthCheckDigit: The check digit for the date of birth; < when unset.
      • documentNumberCheckDigit: The check digit for the document number; < when unset.
      • expirationDateCheckDigit: The check digit for the expiration date; < when unset.
      • personalNumberCheckDigit: The check digit for the personal number (TD3 only); may be null.
  • error: NFCScanError?: Set when the scan did not complete successfully.

Errors

Errors surface on the completion callback as result.error. Wrong-variant calls fail immediately via IncdOnboardingVariant.assertIncludes(.nfc) instead of through this callback.

NFCScanError cases:

  • error: A wrapped IncdError.
  • notAvailable: NFC not available on this OS/device.
  • userDocumentHasNoChip
  • noScanAttemptsRemaining

Was this page helpful?