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
selfieand nocardadds the card back, with a warning. flow.documentslimits which cards are accepted. A card outside the list ends on "Please use your …" instead of a result.flow.require_backasks for the back of the card:off,optional(the user may skip it) orrequired. See Back of the card.
Look and feel
- Colours:
theme.colorstakes hex colours (#RGB,#RRGGBBor#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,roundedorsquare) andtheme.font_family, a font your app or page already loads. - Dark mode:
theme.modeislight,darkorsystem. A colour you set applies in both modes. - Your logo:
branding.logois shown on the intro. On the web, a same-origin,data:orblob: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
languageisen,sworauto(the app's or page's language, then the device's).language_switchshows the flow's own EN / SW control.stringsoverrides any text by its id, per language. Each SDK lists its ids and English and Swahili defaults:STRING_IDSandDEFAULT_STRINGSin@digid/sdk/ui,FlowStringsin 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.
Consent and the result screen
screens.consentshows a checkbox the user must tick before the camera opens, with yourtextand an optionallinkto your privacy notice.screens.result.show: falsereturns to your app as soon as the last step is done.screens.result.fieldslimits the rows the result screen shows.screens.result.downloadoffers 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 oneonEventstream. - Web:
onStep,onComplete,onCancel(withreason: "user"or"host") andonError.
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.