Docs contentsYaliyomo ya nyaraka

Custom screens on the engine

Build your own camera screens: open a session, push frames, render each step update, and finish with the result.

Every digid SDK exposes the engine under the ready-made screens. Use it when you want your own camera UI, or on native Android and iOS, where the engine is what the SDK provides. The engine API is the same everywhere; only the names follow each language.

The engine and the session

  1. Create the engine once per app process. It loads the models, which takes a moment: do it off the main thread.
  2. Apply your licence to it (see Licences and renewal).
  3. Open a session for each verification attempt, with the flow you want.
  4. Push camera frames into the session, one at a time, in order. Each push returns a step update.
  5. Render the update: the step, the guidance line, the overlay.
  6. When the update carries a result, the attempt is done. Close the session.
Flutter Web Android iOS
Engine Digid.create() Digid.create({ models }) Digid.create(context) NidaKyc(modelDirectory:)
Licence applyLicence(token) applyLicence(token) applyLicence(token) applyLicence(_:)
Session newSession(FlowKind.cardOnly()) newSession({ kind: "card_only", require_back: false }) newSession(Flow.CardOnly()) newSession(.cardOnly())
Push a frame session.pushFrame(info, bytes) session.pushFrame(info, buffer) NidaFrameAnalyzer or session.pushFrame(...) NidaCaptureAdapter or session.pushPixelBuffer(...)
Guidance text guidanceText(g, Lang.sw) guidanceText(g, "sw") Digid.guidanceText(g, Lang.SW) NidaKyc.text(for: g, lang: .sw)
Finish session.finish() session.finish() session.finish() / finishJson() session.finish() / finishJSON()

Flows

Flow JSON kind Steps
Card only card_only scan_front, then scan_back if require_back is true
Card then selfie card_then_selfie scan_front, scan_back (if asked), then selfie

Both take require_back (default false). A session reads either a NIDA card or a Tanzanian driving licence; you do not choose in advance.

Frames

A frame is raw pixels plus a small description (FrameInfo): width, height, row_stride (bytes per row, 0 for tightly packed), format, rotation_deg (the clockwise rotation that makes the image upright: 0, 90, 180 or 270), mirrored (true for a mirrored front-camera preview) and timestamp_ms.

format Typical source
nv21 Android CameraX (the analyzer converts for you)
i420 Planar YUV, for example Flutter's camera plugin on Android
bgra8 iOS AVCaptureVideoDataOutput, Flutter's camera plugin on iOS
rgba8 A web canvas, an Android Bitmap
rgb8, gray8 Other sources

Push one frame at a time and drop frames while one is in flight: CameraX's "keep only latest" strategy and AVFoundation's alwaysDiscardsLateVideoFrames do this for you. On the web, CameraSource and scanLoop handle the camera and the pacing.

The step update

Each push returns a StepUpdate:

Field Meaning
step The current step: scan_front, scan_back, selfie or done
guidance What to tell the person right now, as a code (see Guidance codes)
overlay Shapes you may draw: card_quad (the card's four corners) and faces (rectangles), in the frame's own coordinates, before rotation
progress 0 to 1, progress of the current step
step_done The step just finished
result The result, once the whole flow is done; otherwise null

Show the guidance with the SDK's text function rather than your own strings for each code. It covers every code, including the selfie step's prompts, in English and Swahili, and stays right when new codes are added.

Switching cameras

The card steps use the back camera. When step becomes selfie, switch to the front camera and push its frames with mirrored: true. The same session continues.

Timeouts

Each step has step_timeout_s (default 30 seconds). If a step cannot finish in time, the flow carries on with what it has: a back that was not read is skipped and flagged with the back_read check, and the result goes to review rather than pass.

Still photos

To read a card from a single photo (an upload instead of the camera), call readCardImage with the image. It returns the result directly, with the same fields and checks.

Finishing

  • When an update carries result, the flow is complete. You can also call finish() at any time to end the attempt and get the best result so far.
  • finish() returns the typed result; finishJson() (Android) and finishJSON() (iOS) return the same result as JSON text, identical on every platform.
  • On Flutter and Web, build the digid.kyc/1 document from the result for your backend: DigidPayload.build(kyc: result) in Dart, engine.buildPayload(result) on the web.
  • Close the session when you are done with it.

The evaluation cap

In evaluation mode (no valid licence) a session stops after 50 completed sessions in one app run and returns the guidance licence_required. Restart the app to keep testing, or apply a licence.

Errors

A licence that is valid but does not include a feature the flow needs refuses the session with a "feature not licensed" error naming the feature. Evaluation mode never refuses. See Error codes.