> For the complete documentation index, see [llms.txt](/llms.txt)

# NFC for Document report

## Start here

Recent passports, national identity cards and residence permits contain a chip that can be accessed using Near Field Communication (NFC). The Entrust Identity Verification SDKs provide a set of screens and functionalities to extract this information, verify its authenticity and provide the resulting verification as part of a Document report.

NFC chips contain a cryptographically signed version of the document's information which, when validated using the issuing country's public keys, provides a higher level of fraud protection. NFC scanning also vastly improves the end-user experience, halving the turnaround time of verification and returning a 95% pass rate on successful scans.

**NFC is available via our iOS, Android, React Native and Flutter SDKs, and Entrust highly recommends using NFC for identity verification where possible.**

Follow this guide learn how to:

- Configure NFC with Workflow Studio
- Configure the SDKs for NFC extraction
- Interpret the verification results in a Document report

You can view the list of currently [supported documents for NFC](/guide/supported-documents-nfc).

**Please contact your Customer Success manager for additional help with integrating NFC.**

# Using NFC

## Use NFC in Workflow Studio

**We recommended that you enable and manage NFC in Workflow Studio.**

In Studio, NFC extraction is controlled by configuring the Document Capture task in the Workflow Builder.

In the right hand configuration panel, select one of the following options from the NFC dropdown menu:

- Off: NFC extraction will not be required of end-users
- If possible: NFC extraction will be attempted, if possible
- Required: NFC extraction will be enforced, not allowing end-users to finish the flow without a successful reading

<div>
  <img src="./NFC-studio-config.png" />
</div>

When configured to "If possible":

- Studio will instruct the SDKs to prompt end-users to scan their document via NFC (if both the document and the device are NFC capable)
- End-users scanning NFC-enabled documents will be permitted up to 3 failed attempts, after which the verification flow will proceed without NFC extraction, falling back to the captured document image
- If an end-user selects a document without NFC, they will continue the flow without a prompt for an NFC scan

When configured to "Required":

- The verification flow will only display NFC-enabled documents to the end-user
- If a user starts the flow with a non-NFC-compatible device, they will be informed that the device is not compatible
- If a document does not have an NFC chip, the user will be asked to choose another NFC-enabled document, or exit the flow
- After 3 failed NFC extraction attempts, the end-user will be presented with the option to try again or exit the verification flow

Document report tasks linked to this Document Capture task will automatically generate the `issuing_authority` breakdown detailing the NFC verification steps. Any subsequent Facial Similarity tasks will use the applicant's picture present in the NFC chip by default for comparison.

# Configuring NFC in the SDKs

Regardless of whether you are using Workflow Studio or creating a check through the API, NFC extraction must first be configured using our SDKs.

NFC extraction is enabled by default since the release of the following SDK versions:

| SDK          | Version | Technical Documentation                                                          |
| ------------ | ------- | -------------------------------------------------------------------------------- |
| iOS          | 29.1.0  | [ios SDK reference](/sdk/ios/#nfc-capture)                                       |
| Android      | 18.1.0  | [Android SDK reference](/sdk/android/#nfc-capture-using-onfido-studio)           |
| React Native | 9.0.0   | [React Native SDK reference](/sdk/react-native/#nfc-capture-using-onfido-studio) |
| Flutter      | 4.0.0   | [Flutter SDK reference](/sdk/flutter/#nfc-capture-using-onfido-studio)           |

Please refer to the relevant instructions for the detailed steps on how to declare the necessary dependencies and permissions in your application, in particular the [required pre-requisites](/sdk/ios/#pre-requisites) for the iOS SDK.

To activate NFC in SDK versions earlier than those specified in the table above, please refer to the corresponding SDK version's technical reference.

## Start the SDK flow

The SDK flow for a Document report with NFC includes both the standard document capture screens and additional NFC scan screens.

All users will first be presented with the document capture screens. The additional NFC screens will then be presented to the user if both the user's device and the document type support NFC. Otherwise, the user will finish the SDK flow after the document capture step and no NFC scan will be completed.

## Document IDs

On success, the SDK will return a callback which contains an array of document IDs. The document IDs will include:

- the document front image
- the document back image (if the document has 2 sides, for example an ID card)
- the NFC media ID (if the document is supported for NFC and an NFC scan has completed successfully)

#### iOS

```swift
func getDocumentIds(fromResults results: [OnfidoResult]) -> [String]? {
        return results.map({ onfidoResult -> [String] in
            switch onfidoResult {
            case .document(let documentResult):
                guard let nfcMediaId = documentResult.nfcMediaId else {
                    return []
                }
                var ids: [String] = [documentResult.front.id]
                if let backId = documentResult.back?.id {
                    ids.append(backId)
                }
                ids.append(nfcMediaId)
                return ids
            default:
                return []
            }
        }).first
    }

OnfidoFlow(...)
    .with(responseHandler: { response in
        switch response {
            case .success(let results):
                if let documentIds = getDocumentIds(fromResults: results) {
                   // USE DOCUMENT IDS FOR CHECK CREATION
                }
            ...
        }
    })
```

```objc
(NSArray*)getDocumentIds:(NSArray *)flowResults {
    ONFlowResult *flowResult = [flowResults firstObject];
    if (flowResult.type == ONFlowResultTypeDocument) {
        ONDocumentResult *documentResult = (ONDocumentResult *)flowResult.result;
        NSMutableArray *documentIds = [NSMutableArray new];
        [documentIds addObject:documentResult.front.id];
        if (documentResult.nfcMediaId != nil) {
            [documentIds addObject:documentResult.nfcMediaId];
        }
        if (documentResult.back != nil) {
            [documentIds addObject:documentResult.back.id];
        }
        return [NSArray arrayWithArray:documentIds];
    }
    return @[];
}

ONFlow *flow = [[ONFlow alloc] initWithFlowConfiguration:config];
[flow withResponseHandler:^(ONFlowResponse *response) {
    if (flowResponse.results) {
        NSArray *documentIds = [self getDocumentIds:flowResponse.results];
        // Use document IDs for check creation
    } else if (flowResponse.error) {
        // Handle Error
    } else if (flowResponse.userCanceled) {
        // Handle User Canceled Action
    }
}, dismissFlowOnCompletion: /* Dismiss Completion Here */ ];
```

#### Android

```kotlin
override fun userCompleted(captures: Captures) {
    val documentIds = captures.toJson()
    // add the document ids to check creation request body
    add("document_ids", documentIds)
}

private fun Captures.toJson(): JsonArray {
    val array = JsonArray()
    document?.nfcMediaUUID?.let { uuid -> array.add(uuid) }
    document?.front?.let { frontSide -> array.add(frontSide.id) }
    document?.back?.let { backSide -> array.add(backSide.id) }
    return array
}
```

```java
oid userCompleted(@NonNull Captures captures) {
        JsonArray jsonCaptures = capturesToJson(captures);

        // add the document ids to check creation request body
        JsonObject requestBody = new JsonObject();
        requestBody.add("document_ids", jsonCaptures);
}

JsonArray capturesToJson(@NonNull Captures captures) {
        JsonArray array = new JsonArray();
        if (captures != null) {
            Document document = captures.getDocument();
            if (document != null) {
                String nfcMediaUUID = document.getNfcMediaUUID();
                if (nfcMediaUUID != null) {
                    array.add(nfcMediaUUID);
                }
                DocumentSide frontSide = document.getFront();
                if (frontSide != null) {
                    array.add(frontSide.getId());
                }
                DocumentSide backSide = document.getFront();
                if (backSide != null) {
                    array.add(backSide.getId());
                }
            }
        }
        return array;
}
```

#### React Native

```js
    Onfido.start({
          sdkToken: 'sdkTokenFromOnfidoServer',
          flowSteps: {
            welcome: true,
            captureFace: {
              type: OnfidoCaptureType.VIDEO,
            },
            captureDocument: {
              docType: OnfidoDocumentType.DRIVING_LICENCE,
              countryCode: OnfidoCountryCode.USA,
            }
          },
        })
          .then(res =>
            const result = JSON.stringify(res);
            const nfcMediaId = result.document.nfcMediaId ?? result.document.nfcMediaUUID;
            const frontId = result.document.front.id;
            const backId = result.document.back.id;

          )
          .catch(err => console.warn('OnfidoSDK: Error:', err.code, err.message));
```

#### Flutter

```kotlin
private var result: MethodChannel.Result? = null

override fun userCompleted(captures: Captures) {
    // deserialize the received captures as per your needs, for example:
    result?.success(captures.toFlutterResult())
    result = null
}

internal fun Captures.toFlutterResult(): Any {
    val elements = mutableMapOf()
    this.document?.let {
        elements["document"] = it.deserialize()
    }
    this.face?.let {
        elements["face"] = it.deserialize()
    }
    return listOf(elements)
}

private fun Face.deserialize(): Map<*, *> {
    return mapOf("id" to id, "variant" to this.variant.ordinal)
}

private fun Document.deserialize(): Map<*, *> {
    val map = mutableMapOf()
    map["typeSelected"] = this.type.toString().lowercase()
    map["nfcMediaId"] = this.nfcMediaUUID.toString()
    front?.let {
        map["front"] = mapOf("id" to it.id)
    }
    back?.let {
        map["back"] = mapOf("id" to it.id)
    }
    return map
}
```

# NFC results in the Document Report

## Result handling

### Report breakdown

The `issuing_authority` breakdown captures the result of the NFC scan. It asserts whether data on the document matches the issuing authority data and uses the following sub-breakdowns:

- `nfc_passive_authentication` - asserts the data integrity of the NFC data
- `nfc_active_authentication` - asserts whether the document NFC chip is original or cloned

### Result logic

Passive Authentication and Active Authentication are checked whenever supported by the underlying document. Each check can return a result of `clear`, `consider` or `null` as below:

|                           | `nfc_passive_authentication` | `nfc_active_authentication` |
| ------------------------- | ---------------------------- | --------------------------- |
| Not supported by document | `null`                       | `null`                      |
| Unable to read data       | `null`                       | `null`                      |
| Failed                    | `consider`                   | `consider`                  |
| Succeeded                 | `clear`                      | `clear`                     |

The individual results are then combined in the `issuing_authority` breakdown into a single result:

|                                            | `nfc_active_authentication` is `null` | `nfc_active_authentication` is `consider` | `nfc_active_authentication` is `clear` |
| ------------------------------------------ | ------------------------------------- | ----------------------------------------- | -------------------------------------- |
| `nfc_passive_authentication` is `null`     | `null`                                | `consider`                                | `clear`                                |
| `nfc_passive_authentication` is `consider` | `consider`                            | `consider`                                | `consider`                             |
| `nfc_passive_authentication` is `clear`    | `clear`                               | `consider`                                | `clear`                                |

The overall document verification result is influenced by the `issuing_authority` breakdown as follows.
Note that if fallback to Visual checks is disabled, the Issuing Authority section would be the main driver to the overall result.

| Issuing Authority Breakdown | Overall Document Verification |
| --------------------------- | ----------------------------- |
| `null`                      | `rejected`                    |
| `consider`                  | `suspected`                   |
| `clear`                     | `clear`                       |

Note that if the document's NFC data contains the applicant's photograph, this photograph will be used in any subsequent facial similarity checks, if configured.

### Properties

In the [Document check properties](/api/document-report-object/) an `nfc` object is returned which includes the NFC extracted document data.

If NFC is not available, no data will be extracted and the `nfc` object will not be returned.

# Addendum

## Disabling NFC and Removing SDK dependencies

As NFC is enabled by default and library dependencies are included in the build automatically, the following section details the steps required to disable NFC and remove any libraries from the build process.

### iOS

- Disable `Near Field Communication Tag Reading` capability in your app target. You can follow the steps in [Apple's documentation](https://help.apple.com/xcode/mac/current/#/dev88ff319e7)
- Remove any entries relating to the NFC setup from your app target's `Info.plist` file (please refer to the [iOS SDK documentation](/sdk/ios/#nfc-capture-using-onfido-studio))
- Pass the following method to disable NFC in the iOS SDK.

```swift
let config = try! OnfidoConfig.builder()
    .withSDKToken("")
    .withDocumentStep()
    .withNFC(.off)
    .build()
```

```objc
ONFlowConfigBuilder *configBuilder = [ONFlowConfig builder];

[configBuilder withSdkToken:@"YOUR_SDK_TOKEN_HERE"];
[configBuilder withDocumentStep];
[configBuilder withNFC:ONNFCConfigurationOff];

NSError *configError = NULL;
ONFlowConfig *config = [configBuilder buildAndReturnError:&configError];
```

### Android

- Remove any dependencies (with the specified versions) relating to NFC from your build script. Please refer to the [Android SDK documentation](/sdk/android/#nfc-capture-using-onfido-studio)
- Pass the following method to remove the NFC document extraction step from the Android SDK flow.

```kotlin
val config = OnfidoConfig.Builder(this@MainActivity)
   .withSDKToken(“”)
   .withNFC(NFCOptions.Disabled)
   .withCustomFlow(flowSteps)
   .build()
```

```java
OnfidoConfig config = new OnfidoConfig.Builder(context)
    .withSDKToken(“”)
    .withNFC(NFCOptions.Disabled.INSTANCE)
    .withCustomFlow(flowSteps)
    .build()
```

### React Native

- Remove any dependencies relating to NFC. Please refer to the relevant section of the [React Native SDK Reference](/sdk/react-native/#disabling-nfc)
- Include the following initialization option to remove the NFC document extraction step from the React Native SDK flow.

```js
config = {
  sdkToken: “”,
  flowSteps: {
    
  },
  nfcOption: OnfidoNFCOptions.DISABLED
}
```

### Flutter

- Remove any dependencies relating to NFC. Please refer to the relevant section of the [Flutter Reference](/sdk/flutter/#disabling-nfc)
- Include the following initialization option to remove the NFC document extraction step from the Flutter SDK flow.

```js
config = {
  sdkToken: “”,
  flowSteps: {
    
  },
  nfcOption: NFCOptions.DISABLED
}
```