Prerequisites

It is first required to Setup Environment install the SDK into the project follow the details outlined in the Setup Environment

The minimum supported Android version is 21, which supports 99.6% of devices.

The minimum supported iOS version is iOS 13, which supports 99.6% of devices.

Step 1: Initialize the Incode SDK

Fast way SDK Initialize

Before the Incode SDK can be utilized, it must be initialized. Check the following code on how to initialize the Incode SDK on each platform.

public static void IncodeSDKInitialize(Application app) {
  try {

    new IncodeWelcome.Builder(app, Constants.API_URL, Constants.API_KEY)
      .setLoggingEnabled(true)
      .build();

    incodeSDKInitialized = true;
  } catch (Exception exception) {
    incodeSDKInitialized = false;
  }
}

private void setIncodeCommonConfig() {
  CommonConfig commonConfig = new com.incode.welcome_sdk.CommonConfig.Builder()
    .setShowExitConfirmation(true)
    .setShowCloseButton(true)
    .build();

  IncodeWelcome.getInstance().setCommonConfig(commonConfig);
}
func incodeSDKInitialize(api_url: String, api_key: String) {
  IncdOnboardingManager.shared.initIncdOnboarding(url: api_url,
                                                  apiKey: api_key,
                                                  loggingEnabled: true,
                                                  testMode: testMode) { (success, error) in
        print("IncdOnboarding SDK initialization, success: \(success == true), error: \(error?.description ?? "nil")")
        self.dispatchGroup.leave()
    }
}

func setIncodeCommonConfig() {
  IncdOnboardingManager.shared.allowUserToCancel = true
  IncdOnboardingManager.shared.idBackShownAsFrontCheck = true
  IncdOnboardingManager.shared.idFrontShownAsBackCheck = true
}
void IncodeSDKInitialize(API_URL,API_KEY) {
    IncodeOnboardingSdk.init(
        apiKey: API_KEY,
        apiUrl: API_URL,
        testMode: false,
        onError: (String error) {
          print('Incode SDK init failed: $error');
        },
        onSuccess: () {
          print('Incode SDK init success:');
        },
    );
  }

SDK Initialize with session created at backend

If you are creating the session in the backend, the API_URL needs to end with /0/ in order to let our bakcned knows how to manage the request using only the token of the session. You need to initialize the SDK in this way:

public static void IncodeSDKInitialize(Application app) {
  try {

    new IncodeWelcome.Builder(app, Constants.API_URL+"/0/")
      .setLoggingEnabled(true)
      .build();

    incodeSDKInitialized = true;
  } catch (Exception exception) {
    incodeSDKInitialized = false;
  }
}

private void setIncodeCommonConfig() {
  CommonConfig commonConfig = new com.incode.welcome_sdk.CommonConfig.Builder()
    .setShowExitConfirmation(true)
    .setShowCloseButton(true)
    .build();

  IncodeWelcome.getInstance().setCommonConfig(commonConfig);
}
func incodeSDKInitialize(api_url: String, api_key: String) {
  IncdOnboardingManager.shared.initIncdOnboarding(url: api_url+"/0/",
                                                  loggingEnabled: true,
                                                  testMode: testMode) { (success, error) in
        print("IncdOnboarding SDK initialization, success: \(success == true), error: \(error?.description ?? "nil")")
        self.dispatchGroup.leave()
    }
}

func setIncodeCommonConfig() {
  IncdOnboardingManager.shared.allowUserToCancel = true
  IncdOnboardingManager.shared.idBackShownAsFrontCheck = true
  IncdOnboardingManager.shared.idFrontShownAsBackCheck = true
}
  void IncodeSDKInitialize(API_URL,API_KEY) {
	IncodeOnboardingSdk.init(
      apiUrl: API_URL+"/0/",
      onError: (String error) {
        print('Incode SDK init failed: $error');
      },
      onSuccess: () {
        onStartOnboarding();
      },
    );
}

Step 2: Create the session

Next, a session needs to be created in order for the data to be captured. This requires a Configuration ID, which is also known as a flow ID. To configure a flow, check out the getting started guide.

Fast way session creation

private SessionConfig getSimpleFlowSession() {
        SessionConfig sessionConfig = new SessionConfig.Builder()
                .setRegionIsoCode("ALL")
                .setConfigurationId(Constants.CONFIGURATION_ID)
                .build();

        return sessionConfig;
    }
func getSimpleFlowSession() -> IncdOnboardingSessionConfiguration {
  return IncdOnboardingSessionConfiguration(regionCode: "ALL",
                                            configurationId: "PASTE_HERE_CONFIGURATION_ID")
}
OnboardingSessionConfiguration getSimpleFlowSession() {
    IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true); 
    OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(configurationId: CONFIGURATION_ID);
    return sessionConfig;
  }

Setup a session created at backend

If you are creating the session in the backend, you need to set the session token in order to let the SDK save all the information captured during the onboarding to that session.

You need to create a way to share that token from your backend to your frontend, usually this is done by an additional API that you need to create. Once the frontend has the token (SESSION_TOKEN_FROM_BACKEND), you just need to pass it to the SDK. You can do that in this way:

private SessionConfig getSimpleFlowSession() {
        SessionConfig sessionConfig = new SessionConfig.Builder()
                .setRegionIsoCode("ALL")
                .setExternalToken(SESSION_TOKEN_FROM_BACKEND)
                .build();

        return sessionConfig;
    }
func getSimpleWorkflowSession() -> IncdOnboardingSessionConfiguration {
  return IncdOnboardingSessionConfiguration(regionCode: "ALL",
                                            token: SESSION_TOKEN_FROM_BACKEND)
}
    OnboardingSessionConfiguration getSimpleFlowSession() {
    IncodeOnboardingSdk.showCloseButton(allowUserToCancel: true); 
    OnboardingSessionConfiguration sessionConfig = OnboardingSessionConfiguration(token: SESSION_TOKEN_FROM_BACKEND);
    return sessionConfig;
  }

Step 3: Implement the callbacks

During the user's journey to the flow, various callbacks are executed. Custom business logic can be added in these call backs, but showing a custom screen in between steps is not supported.

private IncodeWelcome.OnboardingListener getFlowOnboardingListener() {
        IncodeWelcome.OnboardingListener onboardingListener = new IncodeWelcome.OnboardingListener() {
            @Override
            public void onOnboardingSessionCreated(String token, String interviewId, String region) {
                super.onOnboardingSessionCreated(token, interviewId, region);

                ((MainActivity) activity).interviewId = interviewId;
            }
           
            @Override
            public void onIdFrontCompleted(IdScanResult result) {
                super.onIdFrontCompleted(result);

                Timber.d("onIdFrontCompleted: %s", result);
            }

            @Override
            public void onIdBackCompleted(IdScanResult result) {
                super.onIdBackCompleted(result);

                Timber.d("onIdBackCompleted: %s", result);
            }

            @Override
            public void onIdProcessed(IdProcessResult result) {
                super.onIdProcessed(result);

                Timber.d("onIdProcessed: %s", result);
            }

            @Override
            public void onSelfieScanCompleted(SelfieScanResult result) {
                super.onSelfieScanCompleted(result);

                Timber.d("onSelfieScanCompleted: %s", result);
            }

            @Override
            public void onFaceMatchCompleted(FaceMatchResult result) {
                super.onFaceMatchCompleted(result);

                Timber.d("onFaceMatchCompleted: %s", result);

                executeFaceMatchValidationCheck(result);
            }
            
            @Override
            public void onSuccess() {
                super.onSuccess();

                Timber.d("onSuccess");

                fetchUserScores(interviewId);
            }

            @Override
            public void onError(Throwable error) {
                super.onError(error);

                Timber.d("onError: %s", error);
            }

            @Override
            public void onUserCancelled() {
                super.onUserCancelled();

                Timber.d("onUserCancelled");
            }
        };

        return onboardingListener;
    }
extension MainViewController: IncdOnboardingDelegate {
    
    func onOnboardingSessionCreated(_ result: OnboardingSessionResult) {
        print("onOnboardingSessionCreated, result: \(result)")
        if result.error != nil {
            let interviewId = result.interviewId
        }
    }
    
    func onIdFrontCompleted(_ result: IdScanResult) {
        print("front IdScanResult: \(result)")
    }
    
    func onIdBackCompleted(_ result: IdScanResult) {
        print("back IdScanResult: \(result)")
    }
    
    func onIdProcessed(_ result: IdProcessResult) {
        print("idProcessResult: \(result)")
    }
    
    func onSelfieScanCompleted(_ result: SelfieScanResult) {
        print("onSelfieScanCompleted, result: \(result)")
    }
    
    func onFaceMatchCompleted(_ result: FaceMatchResult) {
        print("onFaceMatchCompleted, result: \(result)")
    }
    
    func onSuccess() {
        print("onSuccess")
        
        fetchUsetScore()
    }
    
    func onError(_ error: IncdFlowError) {
        print("onError, result: \(error)")
    }
    
    func userCancelledSession() {
        print("userCancelledSession")
    }
}
void onSuccessCallback(){
}

void onErrorCallback(String error){
}

void onUserCancelledCallback(){
}

void onIdFrontCompletedCallback(IdScanResult result) {
  print("ID Front");
  print(result);
}

void onIdBackCompletedCallback(IdScanResult result) {
  print("ID Back");
  print(result);
}

void onIdProcessedCallback(String result) {
  print("ID Process");
  print(result);
}

void onSelfieScanCompletedCallback(SelfieScanResult result) {
  print("Selfie Scan");
  print(result);
}

void onFaceMatchCompletedCallback(FaceMatchResult result) {
  print("Face Match");
  print(result);
}

Step 4 - Execute the Flow

private void startFlow() {
  setIncodeCommonConfig();
  SessionConfig sessionConfig = getSimpleFlowSession();
  IncodeWelcome.OnboardingListener onboardingListener = getFlowOnboardingListener();
  IncodeWelcome.getInstance().startFlow(activity, sessionConfig, onboardingListener);
}
func startFlow() {
  setIncodeCommonConfig()
  let sessionConfig = getSimpleFlowSession();
  IncdOnboardingManager.shared.presentingViewController = self
  IncdOnboardingManager.shared.startFlow(sessionConfig: sessionConfig, delegate: self)
}
void startFlow(){
    var sessionConfig = getSimpleFlowSession();
    
    IncodeOnboardingSdk.startFlow(
      sessionConfig: sessionConfig, 
      onSuccess: onSuccessCallback,
      onError: onErrorCallback,
      onUserCancelled: onUserCancelledCallback,
      onIdFrontCompleted: onIdFrontCompletedCallback,
      onIdBackCompleted: onIdBackCompletedCallback,
      onIdProcessed: onIdProcessedCallback,
      onSelfieScanCompleted: onSelfieScanCompletedCallback,
      onFaceMatchCompleted: onFaceMatchCompletedCallback,
      );
  }

Step 5: Process Results

Last but not least, when the user completes the flow, fetch the results and implement the business logic as needed to JUST redirect the user to the screen you need.

They recommended place to apply the business logic to evaluate the onboarding status and gran access to the product you offer is in the backend, please review this explanation of fetch scores in a deep to achieve that.

private void fetchUserScores(String interviewId) {
  IncodeWelcome.getInstance().getUserScore(FAST, interviewId, new GetUserScoreListener() {
    @Override
    public void onUserScoreFetched(UserScoreResult result) {
      Timber.d("onUserScoreFetched: %s", result);

      validateResultWithBusinessLogic(result);
    }

    @Override
    public void onUserCancelled() {
      Timber.d("getUserScore onUserCancelled");
    }

    @Override
    public void onError(Throwable error) {
      Timber.d("getUserScore onError: %s", error);
    }
  });
}

private void validateResultWithBusinessLogic(UserScoreResult result) {
  // TODO - Apply business rules to check the scores of the session
}
func fetchUserScore() {
	IncdOnboardingManager.shared.getUserScore(userScoreFetchMode: UserScoreFetchMode.fast, interviewId: interviewId ,completion: {
  		userScore in
      if(userScore.error != nil) {
      		validateResultWithBusinessLogic()
       }
       else {
         // TODO - Manage fetch user score error
       }
    })
}
    
func validateResultWithBusinessLogic(userScore:UserScore) {
	// TODO - Apply business rules to check the scores of the session
 }
void fetchUserScores() {
  IncodeOnboardingSdk.getUserScore(
    onSuccess: (result) {
  	  validateResultWithBusinessLogic(result);
	  },
    onError: (error) {
			// TODO - Manage getting User Score error
    }
  );
}

void validateResultWithBusinessLogic(result){
}

Working example project

Once you setup your environment to integrate Incode and once you reaf the explanation about the general steps to integrate the SDK into the different availble flavors, we have a working examples on each platform that can be use as a playground to test the Incode's modules available