How-to use Web SDK

Learn how to create a simple identity validation web app using the Incode Web SDK

Prerequisites

Please, you have read the following guides:

Sample Code

You can find sample code for this approach in Code Samples for Web Integrations, it includes a fake_backend.js with all the steps that will be needed to move to a formal backend for production.

Steps

In the first part of this guide, you will learn how to initialize and run an onboarding web app using the Incode Web SDK.
We will use a linear approach, where all Incode verification modules are executed one after the other, as in the following diagram:

This approach is the most convenient for scenarios where you want your users to go through all the Incode modules before they go further on your application.

Setup project

For this guide, you will need the following project structure:

my-incode-app
|__ index.html
|__ app.js
my-incode-app
 |__index.html
 |__main.js
 |__package.json
 |__.env

Setup your HTML

Some SDK methods require an HTML element to contain the UI components. A div element with the id incode-container will hold the SDK components. https://demo-api.incodesmile.com/0/

index.html

<!DOCTYPE html>
<html lang="en" translate="no">
<head>
  <title>Incode WebSdk</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="google" content="notranslate">
  <script src="https://sdk.incode.com/sdk/onBoarding-<<WEB_SDK_VERSION>>.js" defer></script>
  <script src="./app.js" defer></script>
</head>
<body>
  <div id="incode-container"></div>
</body>
</html>
<!DOCTYPE html>
<html lang="en" translate="no">
<head>
  <title>Incode WebSdk</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="google" content="notranslate">
</head>
<body>
	<div id="incode-container"> </div>
	<script type="module" src="/main.js"></script>
</body>
</html>

🚧

Known Issue: DOM mutations by Google Translate

Observe the translate="no"attribute at the html tag and the <meta name="google" content="notranslate"> within the head tag. Make sure to include them in your project to prevent undesired DOM mutations from Google Chrome's Translate functionality that may provoke DOM errors in your integration.

If your application requires multiple languages, please read out guide on how to include and customize String Localizations

Initializing the Web SDK

  • Initialize the Incode Web SDK using the create method
  • Create a new Onboarding Session.
  • Create a reference to the HTML element that will contain the SDK UI components.

app.js

let incode;

async function app(){
	incode = await window.OnBoarding.create({
    apiURL: "{user.DEMO_URL_0}" // API URL provided by Incode
  });  
}

document.addEventListener("DOMContentLoaded", app);
import { create } from '@incodetech/welcome';

let incode;

async function app() {
    incode = create({
      apiURL: "<<DEMO_URL_0>>", // API URL provided by Incode
    });
}

document.addEventListener("DOMContentLoaded", app);

Fetching a session object

Create a session object

An Onboarding Session Token (or just "session token") is required to link all the user information and validation results.

📘 Make sure to read the guide on creating onboarding sessions from your application backend before continuing with this guide:How to Create an Onboarding Session?.

Saving the session token for later

If you already know how to create an onboarding session, you can fetch a new session object from your application backend and save the response in a variable (session) for later use:

let incode;
let session;

async function app(){
  incode = await window.OnBoarding.create({
    apiURL: "{user.DEMO_URL_0}" // API URL provided by Incode
  });  
  
  // Get the session from your backend
  session = await mySessionRequestMethod();  
}

document.addEventListener("DOMContentLoaded", app);
import { create } from '@incodetech/welcome';

let incode;
let incodeSession;

async function app() {
  incode = create({
    apiURL: "<<DEMO_URL_0>>", // API URL provided by Incode
  });

  // Get the session from the backend
  incodeSession = await mySessionRequestMethod();
}

document.addEventListener("DOMContentLoaded", app);

Using the Onboarding session Object

The session object will contain two properties:

{
  token:"abc123",
  interviewId:"xyz098"
}
  • token: the session token that will be sent in every call to the Incode Omni API
  • interviewId: the unique identifier of the current Incode onboarding session

In almost all cases, you will need the full.session object value as an input parameter for the SDK methods. However, specific methods only require the token value. Ensure you read our official SDK Methods reference to know when to use each.

📘

Organize your code:

To maintain a well-organized code, having a function for each step is a good practice.

1.- Check for any aplicable Mandatory Biometric Consent

Laws around the world might require you to get Biometric Consent to continue the process, but keeping track of the exact conditions that apply to your user is hard, that's why we simplified this process by returning a boolean result in our sendFingerprint() method that clearly show you if a biometric consent is necessary and provides the relevant regulationType of such consent.

You can then show the relevant biometric consent using renderBiometricConsent().

In almost all cases your end user will never see this consent, but this will change as privacy laws get more strict.

const incodeContainer = document.querySelector("#incode-container");

// 1.- Check if mandatory consent is required. and show it if it is.
function checkMandatoryConsent() {
  incode.sendFingerprint({ token: incodeSession.token }).then((response) => {
    // Send fingerprint returns a response with the following structure:
    //   {
    //     "success": true,
    //     "sessionStatus": "Alive",
    //     "ipCountry": "UNITED STATES",
    //     "ipState": "ILLINOIS",
    //     "showMandatoryConsent": true,
    //     "regulationType": "US_Illinois"
    // }
    // If the response has showMandatoryConsent and is set to true, we need to show the mandatory consent
    if (response?.showMandatoryConsent) {
      incode.renderBiometricConsent(incodeContainer, {
        token: incodeSession,
        onSuccess: captureCombinedConsent,
        onCancel: () => showError("Mandatory consent was denied"),
        regulationType: response.regulationType,
      });
    } else {
      captureCombinedConsent();
    }
  });
}

📘

International Privacy Laws are Hard

The laws around biometric consent apply to you depending on where the user is from and where the customer is accessing your system—even if they are using a VPN.

Laws can change from country to country and even from state to state, and you might be subject to fines and penalties even if you didn't know you had to get proper consent from the user.

Using this pattern of integration, you can leverage Incode's system to detect if the end user's location is subject to such regulations. Further verifications will be done once we know the user's geolocation via GPS and later when we analyze their ID card to determine their origin.

📘

Capture flow:

Notice that the onSuccess callback it's being used to execute the function corresponding to the next step of the flow to create a "linear" experience for the user.

2.- Show the Combined Consent

Before being able to get anymore information from the end user, you will need to ask for their consent, our combinedConsent module make it easy, please take a look a the documentation , create your first consent and get the consentId from Configuration > Consents

Once armed with the consentId create the following function in your app.js

// 2.- Show the combined consent
//    This consent is created in the dashboard and has to be passed as a parameter
//    to the renderCombinedConsent function.
function captureCombinedConsent() {
  incode.renderCombinedConsent(incodeContainer, {
    token: incodeSession,
    onSuccess: sendGeolocation,
    consentId: consentId, // id of a consent created in dashboard
  });
}

3.- Capture the Geolocation

// 3.- Send geolocation and start the ID capture flow
function sendGeolocation() {
  incode.sendGeolocation({ token: incodeSession.token });
  captureId();
}

4.- Capture and validate an ID card

There are two steps to validate an ID card:

  1. Capture the front and back sides of the ID
  2. Execute the ID validation process

Capture the front and back sides of the ID using the renderCaptureId() method.

The renderCaptureId() method is a ready-to-use component capable of activating the device camera and presenting a capture assistant to capture the Id

The following code shows how to implement the renderCaptureId() method to create a flow for the user to capture both sides of the ID:

// 4.- Capture the ID
function captureId() {
  incode.renderCaptureId(incodeContainer, {
    session: incodeSession, 
    onSuccess: processId,
    onError: showError,
    forceIdV2: false //default to false
  });
}

📘

Important: Omni Dashboard configuration required.

Most of the options and settings for renderCaptureId such as number of capture attempts, manual-capture timeout or optional tutorials are configured from your Incode Omni Dashboard.

renderCamera() expects three arguments:

  • container (HTMLElement): The container HTML element that will hold the UI component. In this case, you can see we have selected the element with id incode-container
  • optionsObject (object): The configuration options for the method:
    • token (object): the full session object
    • onSuccess (function): A callback to be executed after a successful capture.
    • onError (function): A callback to be executed if the number of tries is reached.
    • forceIdv2 (boolean): If you want to forcibly enable the new Id capture experience, set to true, if not, it will dynamically adjust how many of your users it will present the old and the new capture experience.

👍

Requesting permissions for the device camera:

The Web SDK takes care of requesting the use of the device's camera to the user. The camera cannot be activated without the user explicitly allowing its use.

If the user denies the use of the camera, the renderCaptureId() method will trigger the onError callback with the error message DOMException: Permission denied which means the ID capture and validation cannot be performed.

5.- Process the Id

Identity validations and OCR extraction occur on the Incode platform. For that, we need to trigger the processing of the ID using the processId() method:

// 5.- Process the ID
async function processId() {
  return incode.processId({ token: incodeSession.token })
    .then(() => {
      captureSelfie();
    })
    .catch((error) => {
      showError(error);
    });
}

processId() expects one argument:

  • optionsObject (object):
    • token (string): The session token value. As you can see, we are taking the token property value from the session object.

processId() returns a promise. If the promise is resolved, the ID is processed. If it is rejected, it means there was an error trying to process the ID.

In this example, we are using then to execute the next step of the user flow and catch to display the error in the console.

🚧

processId() does not return the result of the validation:

The processId() method does not return neither scores or OCR data of the ID document. Validation scores and OCR data must be requested in your application backend.

6.- Validate the user selfie against the ID

The next step of the validation flow is to compare the face of the user against the photo in the ID. For that, we will use the renderCamera() method one more time:

// 6.- Capture the selfie
function captureSelfie() {
  incode.renderCaptureFace(incodeContainer, {
    session: incodeSession,
    onSuccess: finishOnboarding,
    onError: showError,
    forceV2: false //default to false
  });
}

As you can notice, we are using the same configuration options for the ID capture step, but this time, we are the forceV2 option is slidghtly different in ide is forceIdV2.


📘

Important: Omni Dashboard configuration required.

Most of the options and settings for renderCaptureFace such as number of capture attempts, manual-capture timeout or optional tutorials are configured from your Incode Omni Dashboard.

7.- Mark the onboarding session as completed

Marking an onboarding session as completed tells the Incode platform that the user has finished all flow steps regardless of the scores. This is a critical step because it will tell you how many users went through all the steps from start to finish.

For this, you must call the Mark onboarding complete endpoint from your backend., you will need to pass the session token for the backend to be able to mark the session.

At this point, your app.jsThe file should look like this:

let incode;
let incodeSession;
const incodeContainer = document.getElementById("camera-container");

// 1.- Check if mandatory consent is required. and show it if it is.
function checkMandatoryConsent() {
  incode.sendFingerprint({ token: incodeSession.token }).then((response) => {
    // Send fingerprint returns a response with the following structure:
    //   {
    //     "success": true,
    //     "sessionStatus": "Alive",
    //     "ipCountry": "UNITED STATES",
    //     "ipState": "ILLINOIS",
    //     "showMandatoryConsent": true,
    //     "regulationType": "US_Illinois"
    // }
    // If the response has showMandatoryConsent and is set to true, we need to show the mandatory consent
    if (response?.showMandatoryConsent) {
      incode.renderBiometricConsent(incodeContainer, {
        token: incodeSession,
        onSuccess: captureCombinedConsent,
        onCancel: () => console.log("Mandatory consent was denied"),
        regulationType: response.regulationType,
      });
    } else {
      captureCombinedConsent();
    }
  });
}

// 2.- Show the combined consent
//    This consent is created in the dashboard and has to be passed as a parameter
//    to the renderCombinedConsent function.
function captureCombinedConsent() {
  incode.renderCombinedConsent(incodeContainer, {
    token: incodeSession,
    onSuccess: sendGeolocation,
    consentId: < CONSENT ID >, // id of a consent created in dashboard
  });
}

// 3.- Send geolocation and start the ID capture flow
function sendGeolocation() {
  incode.sendGeolocation({ token: incodeSession.token });
  captureId();
}

// 4.- Capture the ID
function captureId() {
  incode.renderCaptureId(incodeContainer, {
    session: incodeSession, 
    onSuccess: processId,
    onError: console.log,
    forceIdV2: forceV2 // Use the global V2 flag
  });
}

// 5.- Process the ID
async function processId() {
  return incode.processId({ token: incodeSession.token })
    .then(() => {
      captureSelfie();
    })
    .catch((error) => {
     console.log(error);
    });
}

// 6.- Capture the selfie
function captureSelfie() {
  incode.renderCaptureFace(incodeContainer, {
    session: incodeSession,
    onSuccess: finishOnboarding,
    onError: console.log,
    forceV2: forceV2 // defaults to false
  });
}

// 7.- Finish the onboarding
function finishOnboarding() {
  myFinishSessionRequestMethod(incodeSession.token)
    .then((response) => {
    	console.log('Finished');
    })
    .catch((e) => {
      console.log(e);
    });
}

async function app() {
  incode = create({
    apiURL: "<<DEMO_URL_0>>", // API URL provided by Incode
  });

  // Get the session from the backend
  incodeSession = await mySessionRequestMethod();
}

document.addEventListener("DOMContentLoaded", app);
import { create } from '@incodetech/welcome';

let incode;
let session;

const incodeContainer = document.querySelector("#incode-container");

function captureIdFrontSide() {
  incode.renderCamera("front", incodeContainer, {
    token: session,
    numberOfTries: 3,
    onSuccess: captureIdBackSide,
    onError: console.log,
    showTutorial: true,
  });
}

function captureIdBackSide() {
  incode.renderCamera("back", incodeContainer, {
    token: session,
    numberOfTries: 3,
    onSuccess: validateId,
    onError: console.log,
    showTutorial: true,
  });
}

function validateId() {
  return incode.processId({ token: session.token })
    .then(() => {
      captureSelfie();
    })
    .catch((error) => {
      console.log(error);
    });
}

function captureSelfie() {
  incode.renderCamera("selfie", container, {
    token: session,
    numberOfTries: 3,
    onSuccess: () => mySessionFinishMethod(session.token),
    onError: console.log,
    showTutorial: true,
  });
}

async function app() {
  incode = create({
    apiURL: "<<DEMO_URL_0>>"
  });
  
  //Store the session object in a variable for later use
   session = await mySessionRequestMethod();
}

document.addEventListener("DOMContentLoaded", app);

Start the flow

Go to the app() function and add the first step of the flow by calling the captureIdFrontSide() function:

async function app() {
  incode = create({
    apiURL: "<<DEMO_URL_0>>", // API URL provided by Incode
  });

  // Get the session from the backend
  incodeSession = await mySessionRequestMethod();
  
// Run first step in the validation
  checkMandatoryConsent();
}

Testing your app

Your application should be fully functional at this point. Here are some recommendations for making it available for testing.

HTTPS

All HTTP requests executed from the Web SDK are secured. Run your application over HTTPS; otherwise, it may cause mixed content warnings and CORS errors.

Development servers

Incode Web SDK is compatible with most development environments and frameworks like Express and Vite. You can use a local server or make it public so others can test it.

🚧

Testing and production environments:

Please make sure you use the Incode testing environment during your development process. Using the Incode production environment may result in service charges in your account. Please contact us to know more about the service fees.


What’s Next

Now that your identity validation app is complete, it's time to check the results of each onboarding.