• About TrustVision
  • Android SDK
  • iOS SDK
  • Flutter SDK
  • React Native SDK
  • API Client Libraries
  • eKYC Platform
  • Integration Case Studies
  • TS eKYC/FA App
TrustVision API Documentation

Web SDK

Version < 5.x.x (deprecated)

Demo

https://unpkg.com/@tsocial/[email protected]/examples/index.html

Install

CDN

html
<script src="https://unpkg.com/@tsocial/tvweb-sdk@<VERSION>/build/tvweb-sdk.standalone.min.js"></script>

React

properties
npm install @tsocial/tvweb-core @tsocial/tvweb-ui
# or
yarn add @tsocial/tvweb-core @tsocial/tvweb-ui

Angular, Vue, ..

Or the library not React

properties
npm install @tsocial/tvweb-sdk
# or
yarn add @tsocial/tvweb-sdk

Usage

Vanilla JS

javascript
const tv = new TVWebSDK.SDK({
  container: document.getElementById("container"),
  lang: "vi",
  assetRoot: "https://unpkg.com/@tsocial/tvweb-sdk@<VERSION>/assets",
});

// Main functions:
tv.readIDCard({
  frontCamera: false,
  title: "Mặt trước CMND/CCCD",
  titleIcon: "id_card_front.svg",
  description: "Vui lòng đặt CMND mặt trước vào trong khung",
  onSuccess: handleOnSuccess,
  onError: handleOnError,
});

tv.livenessDetection({
  mode: TVWebSDK.Constants.Mode.ACTIVE,
  apiCheck: false,
  // accessKey: "YOUR ACCESS KEY",
  // secretKey: "YOUR SECRET KEY",
  // apiUrl: "YOUR API ENDPOINT",
  onLivenessDetectionDone: handleLivenessDetectionDone,
  onError: (e) => alert(e.code),
});

tv.checkCamera({ frontCamera: true }).then((error) => console.log(error));

React

javascript
import { LivenessDetection, ReadIDCard } from "@tsocial/tvweb-ui";
import { Constants, SettingsContext } from '@tsocial/tvweb-core';
import TrustVisionAPI from '@tsocial/trustvision-sdk';

// get user agent metadata
const userAgentMetadata = UserAgentUtils.getUAMetadata();
// init apiClient for api call
// if you're calling api by yourself, ignore this apiClient
const apiClient = new TrustVisionAPI(accessKey, secretKey, apiUrl, { httpHeaders: userAgentMetadata });

// Liveness Detection component
<SettingsContext.SDKSettingsProvider
  value={{
    lang: "vi",
    assetRoot: "https://unpkg.com/@tsocial/tvweb-sdk@latest/assets",
    apiClient,
  }}
>
  <LivenessDetection
    mode={Constants.Mode.ACTIVE}
    onLivenessDetectionDone={(output) => console.log(output)}
    onError={(e) => console.log(e)}
    captureFrameData
    onProcessing={() => console.log('on processing')}
  />
</SettingsContext.SDKSettingsProvider>

// Read ID Card component
<SettingsContext.SDKSettingsProvider
  value={{
    lang: "vi",
    assetRoot: "https://unpkg.com/@tsocial/tvweb-sdk@latest/assets",
    apiClient,
  }}
>
  <ReadIDCard
    cardSide={Constants.IDCardSide.FRONT}
    enableRecording
    title="Mặt trước CMND/CCCD"
    description="Vui lòng đặt CMND mặt trước vào trong khung"
    frontCamera={false}
    onError={(e) => console.log(e)}
    onSuccess={(output) => console.log(output)}
  />
</SettingsContext.SDKSettingsProvider>

Angular

javascript
// config
// in angular.json, add this to script
"scripts": [
  ...
  "node_modules/@tsocial/tvweb-sdk/build/tvweb-sdk.standalone.min.js"
  ...
]
// usage
declare var TVWebSDK: any;
// the rest example code the same to VanillaJS above

Vue

javascript
import * as TVWebSDK from "@tsocial/tvweb-sdk";
// the rest example code the same to VanillaJS above

API

Read ID Card

This function extracts ID card info.

Params: a single object with these properties

RequiredDescriptionTypeDefault
apiChecknoIf true, sdk will call APIs itself (accessKey, secretKey, apiUrl are needed).booleanfalse
accessKey, secretKey, apiUrlnoKeys to make api callsstring""
frontCameranoTo select front camera or back camerabooleantrue
enableRecordingnoIf enabled, recordedVideos (in onSuccess result) will contain at least 1 videobooleanfalse
cardSidenoSide of ID cardstring (one of [TVWebSDK.Constants.IDCardSide.FRONT, TVWebSDK.Constants.IDCardSide.BACK]TVWebSDK.Constants.IDCardSide.FRONT
frontCardIdno*The id of the front card image returns from onSuccess. This is required when reading back side of ID card (apiCheck is true)string""
titlenoTitle to displaystring""
descriptionnoDescription to displaystring""
onSuccessnoCallback when the process finishes successfully. This object will be returned { image, recordedVideos, apiResult } in which image is the image blob (always returned), recordedVideos is an array of recorded videos ([] or [{ id, frames: [image's base64,...]},...] if enableRecording is true) and apiResult ({ sanityResult, tamperingInfo, cardInfo }) will be returned if apiCheck is true.
- cardInfo: kindly check response.data here
- tamperingInfo: kindly check response.data here
- sanityResult: kindly check response.data here
functionEmpty function
onErrornoCallback when errors happen. An error object will be returned.functionEmpty function

Sample code:

javascript
tv.readIDCard({
  apiCheck: apiCheck,
  accessKey: "YOUR ACCESS KEY",
  secretKey: "YOUR SECRET KEY",
  apiUrl: "YOUR API ENDPOINT",
  frontCamera: false,
  enableRecording: true,
  cardSide: TVWebSDK.Constants.IDCardSide.FRONT,
  frontCardId: inputFrontIdEl.value,
  title:
    cardSide === TVWebSDK.Constants.IDCardSide.FRONT
      ? "Mặt trước CMND/CCCD"
      : "Mặt sau CMND/CCCD",
  description:
    cardSide === TVWebSDK.Constants.IDCardSide.FRONT
      ? "Căn mặt trước CMND/CCCD vào khung"
      : "Căn mặt sau CMND/CCCD vào khung",
  onSuccess: handleReadIDCardResult,
  onError: (e) => {
    resultExtractIdInfoEl.appendChild(
      document.createTextNode(`${JSON.stringify(e, null, 2)}`)
    );
    tv.destroyView();
    readIdCardLoadingEl.style.display = "none";
  },
});

function handleReadIDCardResult({ image, recordedVideos, apiResult }) {
  const apiCheck = selectApiCheckEl.value === "true";

  const imgEl = document.createElement("img");
  imgEl.width = "200";
  imgEl.src = URL.createObjectURL(image);
  resultExtractIdInfoEl.appendChild(imgEl);
  resultExtractIdInfoEl.appendChild(document.createElement("br"));
  resultExtractIdInfoEl.appendChild(
    document.createTextNode(`Recorded videos: ${recordedVideos.length}\n`)
  );

  if (apiCheck) {
    resultExtractIdInfoEl.appendChild(document.createTextNode("API Result:\n"));
    resultExtractIdInfoEl.appendChild(
      document.createTextNode(`${JSON.stringify(apiResult, null, 2)}`)
    );
    const cardSide = selectCardSideEl.value;
    if (cardSide === TVWebSDK.Constants.IDCardSide.FRONT) {
      const frontCardId = apiResult.cardInfo.image1.id;
      inputFrontIdEl.value = frontCardId;
    }
  }

  tv.destroyView();
  readIdCardLoadingEl.style.display = "none";
}

Liveness Detection

This function starts liveness detection flow.

Params: a single object with these properties

RequiredDescriptionTypeDefault
apiChecknoIf true, sdk will call APIs itself (accessKey, secretKey, apiUrl are needed).booleanfalse
modeyesMode to operatestring (one of [TVWebSDK.livenessDetectionMode.ACTIVE, TVWebSDK.livenessDetectionMode.PASSIVE])
accessKey, secretKey, apiUrlnoKeys to make api callsstring""
onLivenessDetectionDoneyesCallback when liveness detection flow is done. This object { frontalFaces, apiCheckPassed, steps, capturedFrames } will be returned.
- steps: all face gestures captured.
- frontalFaces: random frontal faces captured in the background.
- apiCheckPassed: whether all liveness checks passed, appears only when apiCheck is enabled.
- capturedFrames: frames list record liveness process, if captureFrameData not enabled, this returns an empty array.
function
onErrornoCallback when errors happen. An error object will be returned.functionEmpty function
onProcessingnoAvailable from v4.3.0.
From v4.3.0, SDK will resize output images to 400x400 before return. So this is the callback when SDK start resize images. Use to close camera or show loading. The resize process complete on onLivenessDetectionDone.
If apiCheck is enable, this callback also includes api call time.
functionEmpty function
captureFrameDatanoAvailable from v3.9.3.
Whether to record the liveness process or not.
booleanfalse
customErrorsnoAvailable from v3.10.1.
Custom the errors show on SDK. See example below.
objectnull
framesIntervalTimenoAvailable from v4.0.2.
Adjust frames capture per second in captureFrameData mode. Only capture 1 frame in framesIntervalTime. When set to 0, SDK will capture full potential of device can handle.
number (millisecond)180
livenessSettingsnoAvailable from v4.2.1.
This settings come from TS server and depend on your accessKey and secretKey.
When apiCheck enable, this setting will be automated get from TS server and bind to SDK. Anything pass to this props will overwrite settings come with apiCheck.
When you call api by your self, use this api to get client settings, and pass response.data.settings.sdk_settings.active_liveness_settings to this props.
objectnull

Sample code:

javascript
tv.livenessDetection({
  apiCheck: apiCheck,
  mode: livenessDetectionMode,
  accessKey: "YOUR ACCESS KEY",
  secretKey: "YOUR SECRET KEY",
  apiUrl: "YOUR API ENDPOINT",
  onLivenessDetectionDone: handleLivenessDetectionDone,
  onError: (e) => alert(e.code),
});

function handleLivenessDetectionDone(result) {
  const { frontalFaces, apiCheckPassed, steps } = result;
  const apiCheck = selectApiCheckEl.value === "true";
  resultLivenessDetectionEl.innerHTML = "";
  if (apiCheck === false) {
    setTimeout(function () {
      tv.destroyView();
      resultLivenessDetectionEl.appendChild(
        document.createTextNode("Random frontal faces detected: ")
      );
      frontalFaces.forEach((blob) => {
        const imgEl = document.createElement("img");
        imgEl.width = "200";
        imgEl.style.marginRight = "5px";
        imgEl.src = URL.createObjectURL(blob);
        resultLivenessDetectionEl.appendChild(imgEl);
      });
      resultLivenessDetectionEl.appendChild(document.createElement("br"));
      resultLivenessDetectionEl.appendChild(document.createElement("br"));
      resultLivenessDetectionEl.appendChild(
        document.createTextNode("Directional faces:")
      );
      steps.forEach((s) => {
        const imgEl = document.createElement("img");
        imgEl.width = "200";
        imgEl.style.marginRight = "5px";
        imgEl.src = URL.createObjectURL(s.image.blob);
        resultLivenessDetectionEl.appendChild(imgEl);
      });
    }, 500);
  } else {
    tv.destroyView();
    resultLivenessDetectionEl.appendChild(
      document.createTextNode(`apiCheckPassed: ${apiCheckPassed}`)
    );
  }
}

Custom Errors:

javascript
tv.livenessDetection({
  apiCheck: apiCheck,
  mode: livenessDetectionMode,
  accessKey: 'YOUR ACCESS KEY',
  secretKey: 'YOUR SECRET KEY',
  apiUrl: 'YOUR API ENDPOINT',
  onLivenessDetectionDone: handleLivenessDetectionDone,
  onError: e => alert(e.code),
  customErrors={{
    face_too_small: {
      code: 'face_too_small',
      msg: {
        en: 'Face too small',
        vi: 'Đưa camera lại gần',
      },
    },
    face_too_large: {
      code: 'face_too_large',
      msg: {
        en: 'Face too large',
        vi: 'Đưa camera ra xa',
      },
    },
  }}
})

List errors can custom:

javascript
no_face: {
  code: 'no_face',
  msg: {
    en: 'Face not found',
    vi: 'Không tìm thấy khuôn mặt',
  },
},
partial_face: {
  code: 'partial_face',
  msg: {
    en: 'Face out of the box',
    vi: 'Không tìm thấy toàn bộ khuôn mặt',
  },
},
multiple_faces: {
  code: 'multiple_faces',
  msg: {
    en: 'Too many faces',
    vi: 'Quá nhiều khuôn mặt',
  },
},
face_too_small: {
  code: 'face_too_small',
  msg: {
    en: 'Face too small',
    vi: 'Khuôn mặt quá nhỏ',
  },
},
face_too_large: {
  code: 'face_too_large',
  msg: {
    en: 'Face too large',
    vi: 'Khuôn mặt quá to',
  },
},
face_out_of_box: {
  code: 'face_out_of_box',
  msg: {
    en: 'Face is out of box',
    vi: 'Khuôn mặt không nằm trọn vẹn trong khung ảnh',
  },
},

Compare Faces

Compare face from readIDCard result & livenessDetection result.

Params: a single object with these properties

RequiredDescriptionTypeDefault
accessKey, secretKey, apiUrlyesKeys to make api callsstring
image1yesThe id of the front card image returns from onSuccess in readIDCard method.string
image2yesThe id of the first image returns from onLivenessDetectionDone (verifyFaceLivenessResult) in livenessDetection method.string
onSuccessyesSuccess callbackfunction
onErroryesError callbackfunction

Sample code:

javascript
tv.compareFaces({
  accessKey: "e576a662-a94a-4012-9d64-c6f6e81fb711",
  secretKey: "6Z6jgTQSqkwRvpN2n4fzm9Wo3vDAFS2q",
  apiUrl: "https://tv-staging.trustingsocial.com/api",
  image1: "2383fdbe-70aa-470f-9469-96cac7f61ea1",
  image2: "784e8cb3-eb58-497b-aaa9-c02be8b77cf7",
  onSuccess: (rs) => console.log(rs),
  onError: (e) => console.log(e),
});

Destroy View

Stop the camera immediately

Sample code:

javascript
tv.destroyView();

Check Camera

Check the ability to open the camera of the current device.

Params: a single object with these properties

RequiredDescriptionTypeDefault
frontCameranoWhether to check the front camera or the back camerabooleantrue

Return value: a Promise whose fulfillment handler receives an error object when the camera can’t be opened properly or null if no issues occur.

Sample code:

javascript
tv.checkCamera();

Browser compatibility

SDK works best on major browser (Chrome, Firefox, Safari):

Desktop

IEEdgeFirefoxChromeSafariOpera
>11>79>36>53>11>40

Mobile

iOS SafariFacbook Web Browser in iOSFacbook Web Browser in AndroidOpera miniOpera MobileChrome for AndroidFirefox for AndroidUC Browser for Android
>11not supportednot supportednot supportedworks, but there are some unexpected behaviors (browser ask to choose Front/Back camera)>85>79not supported

Please refer Browser compatibility on https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia for more information

WebView Implementer Notes

To make Web SDK work on a WebView, the WebView implementer must supports getUserMedia API and handle camera permission requests correctly.

For Android WebView, the implementer also needs to set the setMediaPlaybackRequiresUserGesture config to false. Otherwise, the camera video cannot be autoplay (the WebView requires a user gesture to play media).

For iOS WebView, there is a known issue which tracked here. You should take a look at that issue before you implement your WebView on iOS.

Possible error objects

javascript
{
  code: 'not_supported',
  msg: {
    en: 'Camera is not well-supported on this device/browser. Please try another one.',
    vi: 'Camera không được hỗ trợ. Vui lòng thử trình duyệt hoặc thiết bị khác.',
  },
},

{
  code: 'camera_timeout',
    msg: {
    en: `Can't access camera. Please check camera permission, try again or try another browser/device`,
      vi:
    'Không thể truy cập camera trong thời gian cho phép. Vui lòng kiểm tra quyền truy cập camera, thử lại hoặc thử trên trình duyệt/thiết bị khác.',
  },
},

{
  code: 'no_permission',
  msg: {
    en: 'Please grant the permission to access the camera.',
    vi: 'Vui lòng cấp quyền để truy cập camera.',
  },
},

{
  code: 'unable_to_load_model',
  msg: {
    en: `Unable to load model on this device/browser. Please try another one.`,
    vi: 'Không thể load model. Vui lòng thử trình duyệt hoặc thiết bị khác.',
  },
},

{
  code: < DOMException > // refer: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#Exceptions
}