Web SDK Integration
Setup, initialization and scanning for the eKYC Web SDK. Executing bundle.js creates the global object window.ekyc.
Prerequisites
| What | Description |
|---|---|
| Assets folder | Somewhere to serve the /ekyc assets folder from. |
| HTTPS | Required for camera access. |
| WebView permissions | On iOS WebViews, enable inline media playback — allowsInlineMediaPlayback in both Flutter and React Native. |
jsQR | Required for QR code functionality. Load it before the SDK bundle. |
HTML Setup
The container element with id cake-ekyc-sdk-container is required and must exist before initialization.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>eKYC Integration</title>
<style>
#cake-ekyc-sdk-container {
width: 100%;
height: 100vh;
position: relative;
}
</style>
</head>
<body>
<!-- Required: SDK container element with specific ID -->
<div class="overlay" id="cake-ekyc-sdk-container"></div>
<!-- Required: eKYC SDK bundle -->
<script src="/ekyc/bundle.js"></script>
<script>
// SDK initialization code goes here
</script>
</body>
</html>Initialize
type SDKConfigParams = {
resourcePath?: string // Optional path to SDK resources
baseUrl: string // Required: Base URL for API requests
token: string // Required: Authentication token
headers?: Record<string, string> // Optional: Additional HTTP headers
}Parameters:
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
baseUrl | string | Yes | — | Base URL for API requests. |
token | string | Yes | — | Authentication token. |
resourcePath | string | No | — | Path to SDK resources. |
headers | Record<string, string> | No | — | Additional HTTP headers. |
const sdk = await window.ekyc.initialize('cake-ekyc-sdk-container', {
baseUrl: '<BASE_URL>',
token: '<SDK_TOKEN>',
resourcePath: '/path/to/resources',
headers: {
'Custom-Header': 'value'
}
})With error handling
async function initializeSDK() {
try {
const container = document.getElementById('cake-ekyc-sdk-container');
if (!container) {
throw new Error('SDK container element not found');
}
if (!window.ekyc) {
throw new Error('eKYC SDK not loaded. Ensure bundle.js is included.');
}
const sdk = await window.ekyc.initialize('cake-ekyc-sdk-container', {
baseUrl: '<BASE_URL>',
token: await fetch('/your-backend/ekyc-token').then((r) => r.text()), // fetched at runtime, never bundled
resourcePath: '/ekyc/resources',
headers: {
'X-Client-Version': '1.0.0',
'X-Platform': 'web',
'X-User-Agent': navigator.userAgent
}
});
return sdk;
} catch (error) {
console.error('SDK initialization failed:', error);
throw error;
}
}WARNING
Fetch token from your backend at runtime — never hardcode it in the page or commit it to source. The token authorizes calls against your tenant.
Scan
scanStart(
types: ('face' | 'front' | 'back' | 'qrcode')[],
opts?: ScanOptions
): Promise<{
nid?: { front?: NIDScanResult, back?: NIDScanResult }
face?: FaceScanResult
qrcode?: QRCodeScanResult
}>Parameters:
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
types | string[] | Yes | — | Which scans to run: face, front, back, qrcode. Order is respected. |
opts | ScanOptions | No | — | Options, mainly for face authentication. |
ScanOptions
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
frontImageId | string | No | — | Image ID from the front scan, used when scanning the back. |
faceauthClientId | string | No | — | Client ID for face authentication. |
faceauthRefId | string | No | — | Reference ID for face authentication. |
isNTB | boolean | No | — | New-to-Bank customer flag. |
currentZoom | number | No | — | Current zoom level. |
timeoutDuration | number | No | — | Timeout duration in milliseconds. |
// Scan front and back of NID card
const result1 = await window.ekyc.scanStart(['front', 'back'])
// Scan face for NTB customer
const result2 = await window.ekyc.scanStart(['face'], {
isNTB: true,
faceauthClientId: 'client-123',
faceauthRefId: 'ref-456'
})
// Scan QR code
const result3 = await window.ekyc.scanStart(['qrcode'])
// Combined scan
const result4 = await window.ekyc.scanStart(['front', 'back', 'face', 'qrcode'], {
isNTB: false,
faceauthClientId: 'client-123',
faceauthRefId: 'ref-456'
})Only the requested scan types appear in the response; everything else is undefined.
Scan Status
interface Status {
frontCompleted: boolean
backCompleted: boolean
faceCompleted: boolean
qrcodeCompleted: boolean
timestamp?: string
frontData?: any
backData?: any
faceData?: any
qrcodeData?: any
}const status = window.ekyc.getScanStatus()
console.log('Front scan completed:', status.frontCompleted)Response Shapes
NIDScanResult
| Field | Type | Description |
|---|---|---|
frontSideImage | object | Front image: id, label, bitmap, response. |
backSideImage | object | Back image, same shape. |
sanityResult | object | Card sanity verdict, score and detected card box. |
cardInfo | object | OCR, MRZ and QR extraction with confidence scores. |
sanityResult.data.card_sanity carries verdict, score and info. cardInfo.data.card_information is an array of CardInformation.
CardInformation
| Field | Type | Description |
|---|---|---|
field | string | Field name. |
value | string | Extracted value. |
confidence_score | number | Overall confidence. |
confidence_verdict | string | Text verdict. |
digit_confidence_scores | number[] | Per-character confidence. |
FaceScanResult
| Field | Type | Description |
|---|---|---|
faces | FaceData[] | Captured faces, each with image and gesture (left, right, portrait). |
sanityResult | SanityResult[] | Portrait sanity verdict and score per image. |
livenessResult | LivenessResult | is_live, score, per-image results and main_image_id. |
QRCodeScanResult
| Field | Type | Description |
|---|---|---|
raw | string | Raw QR code data. |
image | object | Processed image: id, label, bitmap, response. |
Converting bitmaps
bitmap is an ImageData object with two helpers attached:
const blob = await bitmap.toBlob('image/jpeg')
const base64 = bitmap.toBase64('image/jpeg')Error Handling
Scan responses keep the same shape on failure and put detail in the error array. Responses may also carry sdkError:
sdkError?: { code: string; message: string } | {}
// {} -> no SDK-side error
// {code,message} -> the SDK detected a failure you should handlesdkError appears on ImageResponse, the face SanityResult and LivenessResult, the NID sanityResult and cardInfo, and the QR image.response.
WARNING
A successful-looking response can still contain warnings in its error array, and a populated sdkError means the SDK itself rejected the result. Check both — don't treat a resolved promise as a pass.
SDK error codes
| Field | Type | Description |
|---|---|---|
60000 | NID_SANITY_FAILED | NID sanity check failed. |
60001 | NID_TAMPERING_FAILED | NID tampering detection failed. |
60002 | FACE_SANITY_FAILED | Face sanity check failed. |
60003 | FACE_LIVENESS_FAILED | Face liveness check failed. |
QR code error codes
| Field | Type | Description |
|---|---|---|
DOP-675_001 | Scan timeout | "Hết thời gian quét mã. Vui lòng thử lại." |
DOP-675_002 | Scan error | "Không thể quét được mã QR, vui lòng thử lại!" |
Dynamic error codes also arrive from the API in the error array — see Error Codes.
Common issues
| What | Description |
|---|---|
| SDK not loading | Check the script path and that it loads before use. |
| Camera access | Ensure HTTPS and that camera permissions are granted. |
| Container not found | Verify the container element exists in the DOM. |
| Network issues | Check the internet connection and API endpoints. |
if (typeof window.ekyc === 'undefined') {
console.error('eKYC SDK not loaded');
}
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
console.log('Camera access granted');
stream.getTracks().forEach(track => track.stop());
})
.catch(error => {
console.error('Camera access denied:', error);
});Best Practices
- Initialize once and reuse the instance.
- Use
getScanStatus()to monitor progress. - For NID cards, scan the front first, then the back using
frontImageId. - Wrap every scan in try/catch.
- Call
terminate()when done to release the camera and clean up.
Next Steps
- Web SDK Reference — the global object and full TypeScript interfaces
- Web SDK Architecture — layers, modules and key classes