React Native Plugin
Integrations guide
This page sets out step-by-step instructions for setting up your App Drop-in via the React Native Plugin.
Prerequisites
-
You will need your:
fourthlineGithubToken
tenantId
provided by your implementation manager
-
Provide your implementation manager with the GitHub usernames and email addresses of your staff who need access to our repositories.
-
Check the following prerequisites and specifications for your operating system:
Android prerequisites
- Minimum React Native version: 0.69.9
- Minimum supported Android API level: 23
- Minimum Kotlin version: 1.7.20
- Minimum Gradle build tools version: 7.1.3
- Language: The SDK is written in Kotlin but is also compatible with Java.
The plugin contains the following:
Content | Description |
---|---|
Source file Fourthline.kt | Bridges the React Native environment and the fourthline-scanners framework |
fourthline-scanners Android library | Contains the following drop-in modules: • Identity Verification flow • Workflows API • Document, Biometrics, and NFC scanners • Identity data validator and zipper |
fourthline-adapters-json Android library | Provides JSON interfacing with fourthline-scanners |
Android frameworks | Provide functionalities for fourthline-scanners : • fourthline-core : Orchestration and analytics functionality • fourthline-vision : Document and Biometrics scanners • fourthline-nfc : NFC scanner • fourthline-nfc-assets : NFC chip processing functionality • fourthline-kyc : Identity data management functionality • fourthline-sdk • Lottie : Animations functionality |
To upgrade your Gradle build tools version:
1. Search build.gradle
files for entries like classpath 'com.android.tools.build:gradle:
and replace version with 7.1.3
.
2. Search for the gradle
folder, and in the file gradle/wrapper/gradle-wrapper.properties
, change the property URL distributionUrl
to Gradle version 7.4, or later, e.g.: distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
3. To resolve the dependencies on Fourthline's Android SDK, declare and authenticate in Fourthline's Maven repository:
3.1 Add your fourthlineGithubToken
as a Gradle Property for your environment.
Consider configuring the token from your Gradle Home directory or providing it via the command line.
3.2 In your top-level build.gradle
file, link to Fourthline's repository:
allprojects {
repositories {
//...
maven {
url = URI("https://maven.pkg.github.com/Fourthline-com/FourthlineSDK-Android")
credentials {
username = ""
password = property("fourthlineGithubToken").toString()
}
}
}
}
iOS prerequisites
- Minimum iOS version: 12
- Minimum XCode version: 14.3
- Minimum iOS deployment target: 12.4
- MRZ detection in the document scanner requires minimum iOS 13.
The plugin contains the following:
Content | Description |
---|---|
Source files Fourthline.swift and Fourthline.m | Bridge the React Native environment and the FourthlineScanners framework |
FourthlineScanners iOS framework | Contains the following drop-in modules: • Identity Verification flow • Workflows API • Document, Biometrics, and NFC scanners • Location provider • Identity data validator and zipper |
fourthline-adapters-json Android library | Provides JSON interfacing with FourthlineScanners |
iOS frameworks | Provide functionalities for FourthlineScanners : • FourthlineCore : Orchestration and analytics functionality • FourthlineVision : Document and Biometrics scanners • FourthlineNFC : NFC scanner • FourthlineKYC : Identity data management functionality • FourthlineSDK |
Before you set up the plugin, make the following preparations:
1. In the main project's General
> Frameworks, libraries, and embedded content
section, add libswiftVision.tbd
.
2. In the Info.plist
file, add the keys required to access the camera and NFC functionalities:
<key>NSCameraUsageDescription</key>
<string>To verify your identity, please allow us to access your camera once only.</string>
3. Optionally, for the NFC flow, add to the Info.plist
file the keys required to access the NFC functionality:
<key>NFCReaderUsageDescription</key>
<string>To read the chip in your ID document, please enable NFC.</string>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A0000002471001</string>
<string>A00000045645444C2D3031</string>
</array>
4. In the XCode Signing & capabilities
tab, enable the Near Field Communication Tag Reading
capability.
5. Optionally, to record audio in the document and selfie videos, add to the Info.plist
file the key required to access the microphone functionality:
<key>NSMicrophoneUsageDescription</key>
<string>To verify your identity, please allow access to your microphone.</string>
6. Optionally, for the Location module, add to the Info.plist
file the keys required to access the location functionality:
<key>NSLocationWhenInUseUsageDescription</key>
<string>To verify your identity, please allow access to your location.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>To verify your identity, please allow access to your location.</string>
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dictionary>
<key>FourthlineFullAuthorizationPurposeKey</key>
<string>To verify your identity, your exact location is shared with us once only.</string>
</dictionary>
7. If customizing the fonts in the UI, add the font files to your project and to the projects' Info.plist
file:
<key>UIAppFonts</key>
<array>
<string>Your-Font-Medium.ttf</string>
<string>Your-Font-Regular.ttf</string>
</array>
• Fourthline's scanners are designed to be implemented and tested on a real mobile device. Launching them on the iOS simulator throws a scanner error.
Configuration
Age requirement
Configurable
You can dynamically configure the minimum client age requirement and the related checks during Identity Verification workflows.
Document data
Configurable
Discuss with your implementation manager what data to extract from ID document photos via optical character recognition (OCR):
Data type | Description |
---|---|
MRZ data | Document data is extracted from the MRZ only and is processed offline by the SDK. |
MRZ and VIZ data | For greater accuracy, document data is extracted from the MRZ and VIZ and processed by our AI agent in real time. |
Identity data
Configurable
If you want to receive a copy of the identity data gathered by the App Drop-in when it's uploaded to our backend (before case processing), let your implementation manager know.
Real-time feedback
Configurable
Agree with your implementation manager whether you want to enable real-time feedback. The SDKs send the document photos to our backend as soon as they are captured, where we assess the image quality and provide the client feedback in the UI in real time. This ensures higher-quality photos are ultimately uploaded, reduces sendbacks, and improves user experience.
Supported devices
Identity Verification
Setup
To setup the plugin, follow these steps:
1. In your React Native project root, execute the following command:
npm install https://github.com/Fourthline-com/Fourthline-React-Native
2. Go to the iOS
folder, and then execute the following command:
pod install
3. In the source files that will use our plugin, add the following import:
import { NativeModules } from 'react-native';
4. Pass the following JSON configuration to the workflow:
{
"configuration": WorkflowConfiguration,
"customization": WorkflowCustomization
}
WorkflowConfiguration
has the following format:
{
"networkEnvironment": NetworkEnvironment, // To test a workflow locally use .mock, and to test workflow networking use .sandbox
"validationCode": string, // Returned in the Create SDK session response
}
NetworkEnvironment
can have the following values:
Value | Description |
---|---|
production | Live environment |
sandbox | Remote testing environment |
mock | Local testing environment with stubbed data |
To get the ValidationCode
, make a Create SDK session request.
WorkflowCustomization
is an optional field with the following format:
{
"flavor": string
}
To customize the look and feel of the UI, see App UI Customization.
Example
var config = `{
"configuration": {
"validationCode": "123456",
"networkEnvironment": "sandbox"
},
"customization": {
"flavor": {
"colors": ${orcaColors},
"fonts": ${orcaFonts},
"localization": ${orcaLocalization},
"layouts": ${orcaLayout}
}
}
}`;
NativeModules.Fourthline.startWorkflow(config)
.then((msg) => {
// Client has successfully completed the workflow
// No further action required
})
.catch((error) => {
// Extract and process the information received in JSON error string format
var jsonError = JSON.parse(error.message);
});
Success handling
If the workflow is successful, all results are already processed and no additional response is returned.
Error handling
If the workflow is unsuccessful, the following JSON string is returned:
{
"errorCode": number,
"errorDescription": string
}
The following error codes are possible:
Error code | Description | Action |
---|---|---|
800 | Decoding error | Check the errorDescription for more information. |
802 | Invalid or missing font | Check the errorDescription for more information. |
803 | User canceled | The client explicitly canceled the workflow. |
830 | JSON parse error | Check the JSON provided. |
850 | Incorrect configuration | Ensure the workflow is configured correctly. |
870 | Unexpected + message | Inform your implementation manager immediately. |
1000 | ClientRejected | The client isn't eligible for the workflow. You cannot retry. |
1001 | InvalidValidationCode | Make a new Create SDK session request. |
1002 | Module error + message | The client encountered an error in one of the workflow modules. Check the message for more information. |
1003 | ConfigurationNotSupported + message | The workflow created using the validationCode isn't supported. Consider updating to the latest plugin version. |
1004 | InvalidWorkflowStatus | Check if the workflow module is already completed successfully or with an error. |
Testing
To view a mock version, launch the various modules using the following mock validation codes:
Product | Mock validation code |
---|---|
Identity Verification | IDV |
Qualified Electronic Signature module | QES |
Bank Account Verification module | BAV |
Combinations | IDVandBAV IDVandQES IDVandBAVandQES IDVandQESandBAV |
Example code:
NativeModules.Fourthline.startWorkflow(config)
.then((result) => {
// User has successfully completed the Workflow process.
// No further action needed.
})
.catch((error) => {
// Extract and process information from the error String received in JSON format
var jsonError = JSON.parse(error.message);
});
Client Authentication
Setup
The configuration passed has the following JSON format:
{
"customization": CcrCustomization
}
customization
is an optional field. For more information, see App UI Customization.
CcrCustomization
has the following format:
{
"flavor": String
}
Example
import { NativeModules } from 'react-native'
// Use an empty json config if you do not wish to customize the Ccr flow
var config = `{}`;
// or pass the desired customization
var config = `{
"customization": {
"flavor": {
"colors": ${orcaColors},
"fonts": ${orcaFonts},
"localization": ${orcaLocalization},
"layouts": ${orcaLayout}
}
}
}`;
NativeModules.Fourthline.startCcr(config)
.then((msg) => {
// Extract and process information from the result String received in JSON format
var jsonResult = JSON.parse(msg);
})
.catch((error) => {
// Extract and process information from the error String received in JSON format
var jsonError = JSON.parse(error.message);
});
Success handling
If the flow ends successfully, the outcome is returned as a JSON string:
{
"image":"String",
"video":{
"url":"String",
"duration":"String",
"location":{
"latitude":"Number",
"longitude":"Number"
}
},
"metadata":{
"location":{
"latitude":"Number",
"longitude":"Number"
},
"ipAddress":"String",
"region":"String",
"analyticsID":"String",
"osVersion":"String",
"model":"String",
"sdkVersion":"String",
"language":"String",
"osCompromised":"Bool"
}
}
Attributes
Attribute | Description | Required |
---|---|---|
image String | The absolute filepath to the selfie photo. | |
video Object | The selfie video data. Important: Delete the video files when they are no longer needed. | |
video.url String | The absolute url filepath to the selfie video. | |
video.duration String | The length of the selfie video. The selfie scanner duration parameter is always set to default. | |
video.location Object | The coordinates of the selfie video. | |
video.location.latitude String | The latitude of the selfie video. Format: Float between -90 and 90 Example: 45.464664 | |
video.location.longitude String | The longitude of the selfie video. Format: Float between -90 and 90 Example: 45.464664 | |
metadata Object | The metadata of the client's device. | |
metadata.location Object | The coordinates of the client's device. | |
metadata.location.latitude String | The latitude of the client's device. Format: Float between -90 and 90 Example: 45.464664 | |
metadata.location.longitude String | The longitude of the client's device. Format: Float between -90 and 90 Example: 45.464664 | |
metadata.ipAddress String | The IP address of the client's device. | |
metadata.region String | The region code of the client's device. | Auto-filled |
metadata.analyticsID String | The analytics identifier. | Auto-filled |
metadata.osVersion String | The OS version of the client's device. | Auto-filled |
metadata.model String | The client's device model. | Auto-filled |
metadata.sdkVersion String | The version of Fourthline's SDK. | Auto-filled |
metadata.language String | The language of the client's device. | Auto-filled |
metadata.osCompromised Bool | •True : The client's device was jailbroken. • False : The client's device wasn't jailbroken. | Auto-filled |
Error handling
If the flow ends unsuccessfully, the error is returned as a JSON string:
{
"errorCode": Number,
"errorDescription": String
}
You need to handle the following error values:
Error | Description |
---|---|
800 Decoding error | There was an input decoding error. For more information, see errorDescription . |
802 Invalid or missing font | The font provided wasn't found. For more information, see errorDescription . |
803 User canceled | The client explicitly canceled the flow. |
830 Json parse error | We couldn't parse the json provided. |
850 Incorrect configuration | The configuration is incorrect. |
870 Unexpected | An unexpected error occurred. Immediately report this issue to Fourthline along with the errorDescription . |
Testing
Example code:
import { NativeModules } from 'react-native'
var config = `{
"enableTestMe": true
}`;
NativeModules.Fourthline.startCcr(config)
.then((msg) => {
// will never be called
})
.catch((error) => {
// will never be called
});
Document Authentication
Setup
The configuration passed has the following JSON format:
{
"configuration": CdrConfiguration,
"customization": CdrCustomization
}
CdrConfiguration
requires a list of supported countries and has the following format:
{
"supportedCountries": Array
}
CdrCustomization
has the following format:
{
"flavor": String
}
customization
is an optional field. For more information, see App UI Customization.
Example
import { NativeModules } from 'react-native'
// or pass the desired customization
var config = '{
"configuration":{
"supportedCountries": $supportedCountries
},
"customization": {
"flavor": {
"colors": $orcaColors,
"fonts": $orcaFonts,
"localization": $orcaLocalization,
"layouts": $orcaLayout
}
}
}';
NativeModules.Fourthline.startCdr(config)
.then((msg) => {
var jsonResult = JSON.parse(msg);
})
.catch((error) => {
var jsonError = JSON.parse(error.message);
});
Success handling
If the flow ends successfully, the outcome is returned as a JSON string:
{
"document":{
"expirationDate": String,
"images":[
{
"fileSide": String,
"image": String,
"isAngled": Boolean,
"timestamp": String
}
],
"number": String,
"type": String,
"videoRecording":{
"duration": String,
"url": String
}
},
"person":{
"birthDate": String,
"firstName": String,
"gender": String,
"lastName": String,
"nationalityCode": String
}
}
Attributes
Attribute | Description |
---|---|
document Object | The ID document data. |
document.expirationDate String | The ID document expiry date. |
document.images Object | The document photo data. |
document.images.fileSide String | The side of the ID document. |
document.images.image String | The document photo. |
document.images.isAngled Boolean | •True : The photo is tilted. • False : The photo is flat. |
document.images.timestamp String | The timestamp for when the document photo was captured. |
document.number String | The ID document number. |
document.type String | The ID document type. |
document.videoRecording Object | The document video data. |
document.videoRecording.duration String | The length of the document video. |
document.videoRecording.url String | The URL to the document video. |
person Object | The client's personal data. |
person.birthDate String | The client's date of birth. Format: Date YYYY-MM-DD |
person.firstName String | The client's first name. Format: Alphabetical characters, spaces, hyphens, and apostrophes |
person.gender String | The client's sex. • Female : Female in line with ID document • Male : Male in line with ID document • Other : ID document contains a value other than Male or Female • Unknown : ID document contains no gender field |
person.lastName String | The client's last name. Format: Alphabetical characters, spaces, hyphens, and apostrophes |
person.nationalityCode String | The client's nationality. Format: ISO 3166-1 alpha-3 country code |
Error handling
If the flow ends unsuccessfully, the error is returned as a JSON string:
{
"errorCode": Number,
"errorDescription": String
}
You need to handle the following error values:
Error | Description |
---|---|
800 Decoding error | There was an input decoding error. For more information, see errorDescription . |
802 Invalid or missing font | The font provided wasn't found. For more information, see errorDescription . |
803 User canceled | The client explicitly canceled the flow. |
830 Json parse error | We couldn't parse the json provided. |
850 Incorrect configuration | The configuration is incorrect. |
870 Unexpected | An unexpected error occurred. Immediately report this issue to Fourthline along with the errorDescription . |
900 Document expired | The client's ID document has expired. |
901 Document type not supported | The client's ID document type isn't supported. |
902 Issuing country not supported | The ID document issuing country isn't supported. |
903 Nationality not supported | The client's nationality isn't supported. |
904 Person not adult | The client is underage. |
905 Document type is invalid | The client's ID document type isn't valid. |
Testing
Example code:
import { NativeModules } from 'react-native'
var config = '
{
"enableTestMe": true
}
';
NativeModules.Fourthline.startCdr(config)
.then((msg) => {
// will never be called
})
.catch((error) => {
// will never be called
});
Analytics
The FourthlineCore
module collects and processes metrics.
You can set up an analytics observer for the SDK to forward Fourthline events to.
Events are only forwarded when you initialize FourthlineAnalytics
by calling FourthlineAnalytics.initialize(...)
and TrackingConsent
is set to granted
.
- To set up the observer, call
FourthlineAnalytics.setObserver(...)
. - To remove the observer, call
FourthlineAnalytics.removeObserver()
.
import { NativeEventEmitter, NativeModules } from 'react-native'
const analyticsManagerEmitter = new NativeEventEmitter(NativeModules.Fourthline);
// Subscribe
analyticsEventListener = analyticsManagerEmitter.addListener(
'fourthlineAnalytics',
(eventJson) => {
// Handle the Fourthline event
});
// Unsubscribe
analyticsEventListener.remove();
NativeModules.Fourthline.removeListener('fourthlineAnalytics');
Example code for tracked event:
{
"event": string,
"attributes": Object
}
Data observer
To receive notifications for each data group that the SDK uploads to Fourthline and a copy of the data itself, add a data observer:
import { NativeEventEmitter, NativeModules } from 'react-native'
const eventManagerEmitter = new NativeEventEmitter(NativeModules.Fourthline);
// Subscribe
workflowDataListener = eventManagerEmitter(
‘fourthlineWorkflowData’,
(dataJson) => {
// Handle the workflow data
});
// Unsubscribe
workflowDataListener.remove();
NativeModules.Fourthline.removeListener('fourthlineWorkflowData');
The notifications per data type have the following JSON structure:
"idv":{
"document":{
"type":"string",
"number":"string",
"issueDate":"string", // Optional, format YYYY-MM-DD
"expirationDate":"string", // Optional, format YYYY-MM-DD
"images":[
{
"image":"string",
"fileSide":"string",
"isAngled":"boolean",
"timestamp":"string", // Optional, format "YYYY-MM-dd'T'HH:mm:ssZZZZZ"
"location":{
"latitude":"number",
"longitude":"number"
}
}
]
}
}
"idv":{
"documentVideo":{
"url":"string",
"duration":"string", // Default / extended
"location":{ // Optional
"latitude":"number",
"longitude":"number"
}
}
}
"idv":{
"selfie":{
"image":"string",
"timestamp":"string", // Optional
"location":{ // Optional
"latitude":"number",
"longitude":"number"
}
}
}
"idv":{
"selfieVideo":{
"url":"string",
"duration":"string", // Default / extended
"location":{ // Optional
"latitude":"number",
"longitude":"number"
}
}
}
"idv":{
"nfc":{
"image":"string", // Optional
"timestamp":"string",
"location":{ // Optional
"latitude":"number",
"longitude":"number"
},
"mrz":"string",
"dataGroups":[ // Optional
{
"groupNumber":"Int",
"data":"string"
}
]
}
}
"idv":{
"address":{
"street":"string",
"streetNumber":"Int",
"streetNumberSuffix":"string", // Optional
"postalCode":"string",
"city":"string",
"countryCode":"string",
"region":"string" // Optional
}
}
"idv":{
"person":{
"firstName":"string",
"middleName":"string", // Optional
"lastName":"string",
"gender":"string",
"nationalityCode":"string",
"birthCountryCode":"string", // Optional
"birthPlace":"string", // Optional
"birthDate":"string" // Format YYYY-MM-DD
}
}
"idv":{
"deviceMetadata":{
"model":"string",
"sdkVersion":"string",
"osVersion":"string",
"language":"string",
"osCompromised":"string",
"location":{ // Optional
"latitude":"number",
"longitude":"number"
}
}
}
Temporary files
The plugins store some data collected during workflows (e.g. selfie and document videos) in the tmp/fourthline
folder in the client's device filesystem. This is because the videos must remain available until collected, packaged into the case zipfile, and uploaded to our backend.
You must delete the temporary files when they are no longer needed, e.g. after the SDK has uploaded all data to Fourthline or immediately before the app is terminated in:
- Android:
onDestroy()
- iOS:
applicationWillTerminate
import { NativeModules } from 'react-native'
NativeModules.Fourthline.deleteFourthlineFiles().then(() => {
// Fourthline files deleted
});
To integrate your solutions, see the Integration Guides section.
Updated 6 months ago