Docs contentsYaliyomo ya nyaraka

Quick start: Web

Add @digid/sdk to your site, mount the ready-made flow with your licence and send the document to your backend.

@digid/sdk runs the digid engine in the browser, inside a Web Worker, with no uploads. @digid/sdk/ui adds the ready-made screens: intro, camera or photo upload, turn-over, selfie and result.

1. Add the package and host its files

Install @digid/sdk from the package your account gives you: see Get the SDK. Then serve these files from your own origin:

  • the package's dist/ (your bundler resolves the worker next to it; Vite and webpack 5 handle this),
  • the engine's .wasm file, served as application/wasm,
  • the model pack folder, copied as it is.

The page needs HTTPS (the camera needs a secure context). A content security policy needs only 'wasm-unsafe-eval' beyond the usual:

default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; img-src 'self' blob:; style-src 'self'

The SDK fetches only its own files and the models, from your origin. It refuses models from another origin.

2. Mount the flow with your licence

import { mountFlow } from "@digid/sdk/ui";

const flow = mountFlow(document.getElementById("kyc"), {
  models: "/models/",           // the model pack on your origin
  licence: "digidlic1.…",       // your licence key; without it, evaluation mode
  config: {
    flow: { steps: ["card", "selfie"], requireBack: "optional" },
    screens: { result: { download: false } },
  },
  onComplete: ({ result, payload }) => sendToBackend(payload),
  onCancel: ({ step, reason }) => console.log("left at", step, reason),
  onError: (error) => console.error(error),
});

The licence is checked in the browser against the page's origin (location.origin). Local origins such as localhost need a sandbox licence; see Licences and renewal.

The handle has start(), cancel(), setLanguage("en" | "sw" | "auto") and destroy(). With screens.intro.show set to false, the flow starts as soon as it is mounted. Every config key, in camelCase or snake_case, is in the config reference.

3. Read the result

onComplete receives two things:

  • result: the engine's result object, with overall (pass, review or fail), evaluation, the card fields and the checks.
  • payload: the digid.kyc/1 document, as compact JSON text.

With the result screen on, onComplete fires when the user taps its button; with it off, as soon as the result is ready.

4. Send the document to your backend

Send the text as it is. Parsing and re-serialising it can change it and fail the tamper check on your server.

async function sendToBackend(payload) {
  const res = await fetch("/api/kyc", {
    method: "POST",
    headers: { "content-type": "application/json" },
    credentials: "same-origin",
    body: payload,
  });
  if (!res.ok) throw new Error(`KYC upload failed: ${res.status}`);
}

Then check it on the server: Verify on your backend.

5. Report usage

Under a licence the engine counts completed verifications in the page: counts only. Create the engine yourself to report them, and share it with the flow:

import { Digid, loadModels } from "@digid/sdk";

const engine = await Digid.create({ models: await loadModels("/models/") });
await engine.applyLicence("digidlic1.…");
engine.usageSender = (report) =>
  fetch("https://digid.co.tz/api/v1/usage", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ report }),
  }).then((r) => r.ok);
await engine.setUsageStore({
  load: () => localStorage.getItem("digid-usage"),
  save: (state) => localStorage.setItem("digid-usage", state),
});

const flow = mountFlow(element, { nida: engine, onComplete: ({ payload }) => sendToBackend(payload) });
await engine.online(); // sends what is pending

The stored state holds counts, an anonymous counter id and the licence key: no personal data. See Licences and renewal.

Limits on the web

  • No fingerprint capture in the browser: "fingerprints" in flow.steps is skipped with a warning.
  • The download is large the first time: the engine and card models are needed for the card, and the face models load only when a selfie starts. Use preload: "card" (the default), "all" or "none" to choose what loads on mount.

Next