Skip to main content

Real-time Events — Integration

Workflow setup (step configuration)

To support real-time milestone tracking, clients must configure stepIds in their workflow configuration.

What is a stepId?

A stepId identifies a logical grouping of modules (e.g., DigiLocker, Bank Account Verification). When a step completes, the SDK emits a step_ended event with the associated stepId.

How can I configure it?

Let's say your workflow looks like:

Module X → Module 1 → Module 2 → Module 3 → Module 4 → Module Y

If Modules 1 through 4 belong to a logical step (e.g., digilocker), then add the same stepId (e.g., "digilocker") to each of them.

Sample workflow JSON

[
{ "id": "module_x", "type": "typeX", "properties": {}, "variables": [] },
{ "id": "module_1", "type": "type1", "stepId": "digilocker", "properties": {}, "variables": [] },
{ "id": "module_2", "type": "type2", "stepId": "digilocker", "properties": {}, "variables": [] },
{ "id": "module_3", "type": "type3", "stepId": "digilocker", "properties": {}, "variables": [] },
{ "id": "module_4", "type": "type4", "stepId": "digilocker", "properties": {}, "variables": [] },
{ "id": "module_y", "type": "typeY", "properties": {}, "variables": [] }
]

Workflow Builder

  • The stepId field can be found in the properties of the modules.
  • If your workflow is an existing workflow as of 21 May 2025, it will not automatically add stepId to the workflow. You can enable it in each of the modules using a toggle.
  • If you want to add stepId to all the modules, you can reimport the workflow.
  • For Supermodules: stepId auto-filled with snake_case of Supermodule name.
  • For Simple Modules: stepId auto-filled with snake_case of Module name.
  • You can manually override these values if needed. If a stepId is manually overwritten, it will retain that value and no longer take the value from the name of the module, unless it is toggled on and off.

Event: step_ended

When is it triggered?

  • When the last module of a step with a defined stepId completes.
  • When transitioning from one step to a new step (stepId change detected).

Sample payload

{
"schemaVersion": "1.0.0",
"eventName": "step_ended",
"timestamp": "2025-04-21T10:35:40.321Z",
"sdkVersion": "0.45.0",
"transactionId": "transactionId_1234",
"workflowId": "onboarding",
"workflowVersion": "1.0.0",
"appId": "abcdef",
"stepId": "digilocker",
"metadata": {}
}

SDK integration: receiving events

Clients can use the SDK-provided addEventListener API to subscribe to real-time milestone events.

Android
Java
// [Recommended] Attach event listeners before launching HyperKYC SDK
HyperKyc.addEventListener(jsonObject -> {
// Handle the step_ended event
// ....
return Unit.INSTANCE;
});

// Remove all event listeners after receiving the SDK response from HyperKYC SDK
HyperKyc.removeAllEventListeners();
Kotlin
// [Recommended] Attach event listeners before launching HyperKYC SDK
HyperKyc.addEventListener { event ->
// Handle the step_ended event
}

// [Recommended] Remove all event listeners after receiving the SDK response from HyperKYC SDK
HyperKyc.removeAllEventListeners()
iOS
// [Recommended] Attach event listeners before launching HyperKYC SDK
HyperKyc.addEventListener { event in
// Handle the step_ended event
}

// [Recommended] Remove all event listeners after receiving the SDK response from HyperKYC SDK
HyperKyc.removeAllEventListeners()
Web
// [Recommended] Attach event listeners before launching HyperKYC SDK
HyperKYCModule.addEventListener((event) => {
// Handle the step_ended event
})

// [Recommended] Remove all event listeners after receiving the SDK response from HyperKYC SDK
HyperKYCModule.removeAllEventListeners()
Flutter
// [Recommended] Attach event listeners before launching HyperKYC SDK
HyperKyc.addEventListener(listener: (event) {
// Handle the step_ended event
});

// [Recommended] Remove all event listeners after receiving the SDK response from HyperKYC SDK
await HyperKyc.removeAllEventListeners();
Advanced use case [Flutter ↔ Android]

You only need to implement the setup below if:

  • You're targeting devices where:
    • "Don't Keep Activities" is enabled, or
    • Low-memory scenarios are likely

Without this setup, addEventListener() and removeAllEventListeners() may stop working when navigating between native and Flutter screens in the above mentioned scenarios (Don't Keep Activities enabled or Low Memory scenarios).


Setup for reliable event handling (advanced use cases)

In MainApplication.java

@Override
public void onCreate() {
super.onCreate();
FlutterEngine flutterEngine = new FlutterEngine(this);
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
);
FlutterEngineCache.getInstance().put("unique_engine_id", flutterEngine);
}

In MainActivity.java

public class MainActivity extends FlutterActivity {
@Override
public FlutterEngine provideFlutterEngine(Context context) {
return FlutterEngineCache.getInstance().get("unique_engine_id");
}
}
tip

Reuse an existing cached engine if you already use one — no need to initialize a new one.


FAQ

QuestionAnswer
Do I need this setup in all cases?No. Only if your app uses Flutter + native Android and may run on devices with aggressive memory clearing.
What happens without this setup?addEventListener() and similar callbacks may stop working after FlutterActivity gets destroyed.
We already use a cached FlutterEngine. Can we reuse it?Yes, reuse the same engine name.
Is this needed for iOS?No. iOS retains the Flutter engine across transitions by default.

Risk assessment

TouchpointDescriptionRiskImpact
App Startup TimeSlightly slower due to FlutterEngine initLow~30–80ms
Memory UsageOne FlutterEngine stays in memoryLow–Medium~5–15MB
Plugin ConflictsSharing engine with other pluginsVery LowN/A
Dev EffortMinor changes to MainActivity and MainApplicationLow~10–15 lines
If Setup is SkippedEvent listeners may stop working in "DKA-enabled" and "Low-Memory" scenarios where Flutter Activity gets destroyed.HighEvent drop-offs in the mentioned edge cases.

Summary table

RequirementPurposeOptional?iOS Impact?Can Be Shared?
provideFlutterEngine() overrideKeeps Flutter alive across native screensOnly if neededNot neededYes
FlutterEngineCache.put(...)Globally accessible engineOnly if neededNot neededYes

Final recommendation

  • Recommended: Add the setup only if your app frequently navigates between Flutter and native Android screens and you anticipate low-memory situations or "Don't Keep Activities" to be relevant for your user base.
  • If a cached engine already exists, reuse it to reduce duplication.
  • No action required for iOS — FlutterEngine detachment isn't an issue there.
React Native
// Import HyperKyc from react-native-hyperkyc-sdk
import HyperKyc from 'react-native-hyperkyc-sdk';

// [Recommended] Attach event listeners before launching HyperKYC SDK
HyperKyc.addEventListener((event) => {
// Handle the step_ended event
});

// [Recommended] Remove all event listeners after receiving the SDK response from HyperKYC SDK
HyperKyc.removeAllEventListeners();

Notes & clarifications

  • addEventListener() is not the same as DOM event listeners; it simply acts as a callback mechanism.
  • removeAllEventListeners() clears any internal references — must be called at the end of the journey to avoid dangling references.
  • Calling removeAllEventListeners inside an event listener does not cancel pending future events (in Android & Web platforms, yet).

Best practices

  • Attach event listeners before launching the HyperKYC SDK.
  • Do not execute blocking code (e.g., synchronous heavy logic) inside the event listener callback.
    • Especially important for JavaScript-based environments that run on a single thread.
    • Use async/await, setTimeout, or background queues.
  • Do not execute main-thread blocking code inside the event listener callback.
  • Always call removeAllEventListeners() after SDK completion to avoid memory leaks.

Feature support matrix

ScenarioWebAndroidiOSFlutterReact Native
Attach one event listenerYesYesYesYesYes
Main thread blocking code in listener (synchronous/asynchronous)NoNoNoNoNo
Background thread blocking code in listener (synchronous)NoYesYesNoNo
Background thread non-blocking code in listener (async/deferred)YesYesYesYesYes
Attach multiple listenersYesYesYesYesYes
Remove all event listenersYesYesYesYesYes
Remove individual listenerNoNoNoNoNo
removeAllEventListeners inside an event listenerFutureFutureYesFutureFuture
Event drop-offs post SDK completion (SDK closes before triggering all event listeners)No dropsFutureNo dropsFutureFuture
App is restarted (e.g., permissions updated through settings app)NoNoNoNoNo
Attach event listeners through Worker threads or ServicesNAFutureNAFutureFuture
Was this helpful?
Ask AI

Ask anything about the internal documentation

AI answers are based on internal documentation. Verify critical information.