Docs contentsYaliyomo ya nyaraka

Drop-in screens and config

Open the ready-made flow with one config that works the same on every platform, and make it look like your app.

The Flutter and Web SDKs ship the ready-made screens: intro, consent, card camera (front, then the back if asked), selfie, fingerprints (Flutter) and result. You open the flow, pass one config, and get the result and the digid.kyc/1 document back.

One config everywhere

The config is a JSON-compatible object with the same keys on every platform: snake_case in JSON, and the language's own style in code (requireBack in Dart and TypeScript). Every key is optional; an empty config gives the digid look and the full flow.

{
  "flow": {
    "steps": ["card", "selfie", "fingerprints"],
    "documents": ["nida", "driving_licence"],
    "require_back": "off",
    "fingerprints": { "hand": "ask" }
  },
  "engine": { "step_timeout_s": 30, "expiry_policy": "review" },
  "language": "auto",
  "language_switch": true,
  "strings": { "en": {}, "sw": {} },
  "theme": {
    "mode": "light",
    "colors": { "primary": "#000000", "accent": "#3F48FD" },
    "font_family": null,
    "radius": 24,
    "button_shape": "pill"
  },
  "branding": { "logo": null, "powered_by": true },
  "screens": {
    "intro": { "show": true, "title": null, "body": null },
    "consent": { "show": false, "text": null, "link": null },
    "result": { "show": true, "fields": null, "download": true },
    "manual_capture_after_s": 6,
    "haptics": true
  }
}

Keep the config in your backend or remote config if you want to change the flow without a release. In Dart, DigidFlowConfig.fromJson(json) reads it; on the web, mountFlow takes the object or the JSON text. Every key, its type and default is in the config reference.

Steps

  • The order is fixed: card, then selfie, then fingerprints, then the result. Leave a step out to skip it.
  • A selfie needs the card, because the face is matched to the card's photo. A config with selfie and no card adds the card back, with a warning.
  • flow.documents limits which cards are accepted. A card outside the list ends on "Please use your …" instead of a result.
  • flow.require_back asks for the back of the card: off, optional (the user may skip it) or required. See Back of the card.

Look and feel

  • Colours: theme.colors takes hex colours (#RGB, #RRGGBB or #RRGGBBAA) for the button (primary, on_primary), links and toggles (accent), page and cards (background, surface), text (text, muted), the camera's instruction box (overlay, on_overlay), the camera brackets and oval (frame, frame_ready) and the status colours (success, warning, danger).
  • Shape and type: theme.radius (0 to 64), theme.button_shape (pill, rounded or square) and theme.font_family, a font your app or page already loads.
  • Dark mode: theme.mode is light, dark or system. A colour you set applies in both modes.
  • Your logo: branding.logo is shown on the intro. On the web, a same-origin, data: or blob: URL keeps the page offline.

On the web the flow's root has the class digid-flow, and the theme is a set of CSS custom properties on it (--digid-primary, --digid-accent, --digid-radius and so on), so you can also theme it in your stylesheet:

.digid-flow { --digid-accent: #0a7f5a; --digid-radius: 12px; }

Language and text

  • language is en, sw or auto (the app's or page's language, then the device's).
  • language_switch shows the flow's own EN / SW control.
  • strings overrides any text by its id, per language. Each SDK lists its ids and English and Swahili defaults: STRING_IDS and DEFAULT_STRINGS in @digid/sdk/ui, FlowStrings in the Flutter plugin.
{ "strings": { "en": { "use_camera": "Scan my ID" }, "sw": { "use_camera": "Soma kitambulisho changu" } } }

Strings are plain text. The flow never puts markup or engine values into them.

  • screens.consent shows a checkbox the user must tick before the camera opens, with your text and an optional link to your privacy notice.
  • screens.result.show: false returns to your app as soon as the last step is done.
  • screens.result.fields limits the rows the result screen shows.
  • screens.result.download offers the document as a JSON file on the result screen, saved on the device with no upload. Turn it off in production: the document is meant for your backend, not for the person being verified.

Progress and errors

  • Flutter: onStepChanged (intro, card front, card back, selfie, fingerprints, result), onCompleted, onCancelled, onError, or one onEvent stream.
  • Web: onStep, onComplete, onCancel (with reason: "user" or "host") and onError.

Errors such as a refused camera are shown on the flow's own screens as well; your callback is for logging and analytics.

What the config cannot change

Some things protect your customers and the integrity of the results, and no config changes them:

  • Evaluation marking. Without a valid licence, results are watermarked, tagged "Evaluation" and never better than review. Those strings cannot be overridden.
  • On-device processing. No option makes the flow upload anything.
  • The liveness check is always part of the selfie.
  • No engine internals on screen. The screens show verdicts, never the numbers behind them.

Validation

Unknown keys are ignored, and invalid values (a bad colour, an unknown step) fall back to their default. Both print a warning in debug builds; neither ever crashes the flow.