Skip to main content
The web flow has three pieces. Only the first is code you write:
  • TypeScript SDK (@mbkyc/sdk) — imported by your web app. The only piece your application touches.
  • Browser extension (Chrome/Edge) — bridges the page to the local helper.
  • Native host (mbkyc-web-host) — a small desktop helper, started by the browser, that talks to the local smart card and fingerprint hardware.
The page never talks to the host directly: page → extension → native host.

Download the example

A self-contained React + Vite app. Fill in src/config.ts, point MBKYC_NPM_REGISTRY at the MBKYC npm registry (your proxied repo.client.ae host), and npm install && npm run dev.

Prerequisites

@mbkyc/sdk alone is not enough. The end-user machine must also have the browser extension and the mbkyc-web-host native host installed (ship the host with your desktop installer — .deb/.rpm/.pkg/.msi). Card reads and fingerprint capture additionally require the matching desktop services — the PC/SC service and your vendor fingerprint service — which the native host talks to.
Installing the mbkyc-web-host package registers the Chrome and Edge native-messaging host manifest for you, system-wide — every installer format does it (.pkg/.deb/.rpm post-install, .msi/Chocolatey via the registry). There’s no manual manifest step; once the package is installed the browser can discover and launch the host.

Install

npm install @mbkyc/sdk
# or
pnpm add @mbkyc/sdk

Token signer

The SDK never holds your API secret. Supply a tokenSigner: when the SDK needs a JWT, it hands you the header.payload bytes; you return the raw signature — typically by forwarding the bytes to your backend, which holds the secret.
import type { TokenSigner } from '@mbkyc/sdk';

const tokenSigner: TokenSigner = {
  async sign(signingInput: Uint8Array): Promise<Uint8Array> {
    const res = await fetch('/api/mbkyc/sign', { method: 'POST', body: signingInput });
    return new Uint8Array(await res.arrayBuffer());
  },
};

Initialize & validate

import { MBKYCClient } from '@mbkyc/sdk';

const client = new MBKYCClient();

await client.init({
  baseUrl: 'https://api.client.ae',
  apiKeyId: 'key-id',
  tokenSigner,
  logConfig: { logDir: '/var/log/myapp' }, // maxFileSizeBytes?, maxFiles? optional
  // timeoutMs?  (default 30000) · extraHeaders?  (max 5)
});

const readers = await client.listSmartcardReaders();
await client.registerDevice('lobby-kiosk');

const result = await client.validate({
  kind: 'emiratesIdManual',
  idNumber: '784-XXXX-XXXXXXX-X',
  documentNumber: '...',
  nationality: 'ARE',
});

await client.deInit();

Lifecycle

new MBKYCClient(options?)
  → await client.init(config)   // once, before any operation
  → operations …                // getInfo, list*, validate, registerDevice, …
  → await client.deInit()       // tear down; a fresh init() may follow
getInfo() (host version + capabilities) is the one call that does not require init() — use it to detect whether the host/extension are installed.

Operations

MethodReturnsNeeds init()?
getInfo()HostInfono
registerDevice(name)voidyes
checkRegistration()'active' | 'inactive' | 'not_found'yes
listSmartcardReaders()ReaderInfo[]yes
listFingerprintReaders()ReaderInfo[]yes
validate(request)VerificationResultyes
exportLogs(outputPath)voidyes
cancel()void

Validation requests

A validate(request) call selects the document and capture mode through the request’s kind. The requests, grouped by document:
The emiratesIdCard and fingerprint variants need the matching desktop service reachable through the native host — the PC/SC service for card reads and your vendor fingerprint service for biometrics — in addition to the browser extension and mbkyc-web-host. Manual entry needs no hardware or service.
Manual entry — no hardware required.
// Manually entered Emirates ID details.
{ kind: 'emiratesIdManual', idNumber, documentNumber, nationality,
  dateOfBirth?, issueDate?, expiryDate?, fingerprint?, clientReferenceId? }
Card read — needs a smart card reader + the PC/SC service (via the native host). Get readerId from listSmartcardReaders().
// Read the Emirates ID chip from a smartcard reader.
{ kind: 'emiratesIdCard', readerId, cardDipTimeoutMs?, fingerprint?, clientReferenceId? }
+ Fingerprint — add the fingerprint field to either Emirates ID request (emiratesIdCard or emiratesIdManual) for a biometric match. Needs a fingerprint sensor + its service; see Biometrics below.
VerificationResult is { success, message, data?, clientReferenceId? }.

Biometrics

Attach a fingerprint to an Emirates ID request:
const result = await client.validate({
  kind: 'emiratesIdCard',
  readerId: scReader.id,
  fingerprint: {
    readerId: fpReader.id,
    recommendationCallback: {
      async onFingerRecommendation(recommendedFingers /* Finger[] */) {
        // backend's quality-ranked list (best first); may be empty if not enrolled
        return FingerSelection.recommended(recommendedFingers[0]);
        // or FingerSelection.custom(finger) / FingerSelection.cancel()
      },
    },
    captureTimeoutMs: 10_000,
  },
});

Errors

Failures reject with an MBKYCError:
  • error.code — symbolic display code (e.g. "E9900")
  • error.numericCode — numeric code (e.g. 9900)
  • error.error — the typed ErrorCode; compare against the exported per-module buckets (vendor.EXTENSION_NOT_FOUND is raised when the extension is not installed)
See the error reference.
The SDK targets a fixed extension ID. Only pass new MBKYCClient({ extensionId }) if you ship a private fork of the extension under a different keypair (which also requires updating the native host manifest).

Reference

The full operation list is in the Operations table above. Shared value types — ReaderInfo, RegistrationStatus, VerificationResult, Finger, FingerSelection, config — are documented in Data types, and the cross-platform map in the API overview. Export logs writes a tar.zst archive for support:
await client.exportLogs('/tmp/mbkyc-logs.tar.zst');