# Custom Module

The Custom Module pauses a Workflow and hands control to your application, which runs custom logic and returns a result that determines how the Workflow continues. It does this by handing your app a `callbackName`, then resuming the Workflow at the next node once you report a result. It exists only inside dashboard-defined Workflows, not in locally built flows.

For an overview of this module and how it works, see [Custom Module](https://developer.incode.com/docs/custom-module).

Unlike most modules, Custom Module is available only through the Workflows API. You must use [integration Pattern​ 3](https://developer.incode.com/docs/android-common-implementation-patterns#pattern-3-run-flows-configured-in-dashboard) to add it. It cannot be added to a local `FlowConfig`. You place it in a Workflow in Dashboard, and it surfaces in the SDK through a listener callback rather than a `FlowConfig.Builder` method.

This module is available for SDK 5.42.0 and later.

## Add Custom Module

1. In Dashboard, [add a Custom Module node to your Workflow](https://developer.incode.com/docs/custom-module-dashboard) and set its `callbackName`. This is just a string the SDK delivers to your app. On Android, there is no automatic function invocation. Your app decides how to interpret the value: for example, by mapping it to a method or branching on it.
2. Activate the Workflow and note its ID.
3. In your app, start the session with the Workflows API. Set the Workflow ID with `SessionConfig.Builder.setConfigurationId(workflowId)`, then call `IncodeWelcome.startWorkflow(context, sessionConfig, onboardingListener)`.&#x20;
4. Handle the module by overriding `onCustomModuleStarted` on your `OnboardingListener`. If you don't override it, the default implementation does nothing, and the Workflow will not advance past the node. Always provide an implementation that calls `onCustomModuleCompleted`.

### Example

The example below starts a session with a Workflow ID, overrides `onCustomModuleStarted` to run custom logic based on `callbackName`, and reports the result with `onCustomModuleCompleted`.

```kotlin
val sessionConfig = SessionConfig.Builder()
    .setConfigurationId(workflowId)
    .build()

val listener = object : IncodeWelcome.OnboardingListener() {
    override fun onCustomModuleStarted(
        callbackName: String,
        onCustomModuleCompleted: (CustomModuleStatus) -> Unit
    ) {
        // Run your custom logic based on callbackName, then report a result.
        val status = runCustomLogic(callbackName)
        onCustomModuleCompleted(status)
    }

    override fun onError(error: Throwable) {
        // Handle errors.
    }
}

IncodeWelcome.getInstance().startWorkflow(activityContext, sessionConfig, listener)
```
```java
SessionConfig sessionConfig = new SessionConfig.Builder()
    .setConfigurationId(workflowId)
    .build();

IncodeWelcome.OnboardingListener listener = new IncodeWelcome.OnboardingListener() {
    @Override
    public void onCustomModuleStarted(
        String callbackName,
        Function1<CustomModuleStatus, Unit> onCustomModuleCompleted
    ) {
        // Run your custom logic based on callbackName, then report a result.
        CustomModuleStatus status = runCustomLogic(callbackName);
        onCustomModuleCompleted.invoke(status);
    }

    @Override
    public void onError(Throwable error) {
        // Handle errors.
    }
};

IncodeWelcome.getInstance().startWorkflow(activityContext, sessionConfig, listener);
```

## Configuration Options

Custom Module has no client-side `Builder` options. Its only setting, the `callbackName`, is configured on the Custom Module node in the Workflow in Dashboard. The SDK delivers that name to your app at runtime.

For the Workflow APIs that drive it, see `IncodeWelcome` and `SessionConfig.Builder` in [API Reference](https://developer.incode.com/docs/android-api-reference).

## Result

There is no result payload object. The module signals through the `CustomModuleListener.onCustomModuleStarted(callbackName, onCustomModuleCompleted)` callback on your `OnboardingListener`. You then call `onCustomModuleCompleted` with a `CustomModuleStatus` to report the outcome of your custom logic. Once you report a status, the SDK submits it and advances the Workflow to the next node.

`CustomModuleStatus` is an Enum with the following values:

- `OK`
- `FAIL`
- `WARN`
- `UNKNOWN`

Errors surface via `OnboardingListener.onError(Throwable)`. There is no module-specific exception subtype for Custom Module.

For the full callback and status definitions, see `CustomModuleListener` and `CustomModuleStatus` in [API Reference](https://developer.incode.com/docs/android-api-reference).
