# Digia Moengage Integration

***

The Digia MoEngage plugin intercepts **MoEngage self-handled in-app** campaign payloads and pipes them directly into Digia's rendering engine. When a campaign triggers, the plugin maps the incoming payload to your custom UI designs built in Digia Studio, instantly rendering a 100% native experience on the device—no WebViews required.

This guide walks you through the end-to-end integration process—covering SDK installation, plugin initialization, and how to map your dashboard campaigns to Digia's native components.

## 1. Prerequisites

Before integrating, ensure you have:

* **Digia Access Key**: Log in to [Digia Studio](https://app.digia.tech), open your project, and copy your key from **Settings → App Settings**.
* **Active Dashboard Account**: Ensure you have an active MoEngage workspace with access to your App/Account IDs.
* **MoEngage SDK**: Installed and initialized (see [Flutter](https://developers.moengage.com/hc/en-us/articles/20661421128084-Getting-Started-with-Flutter-SDK), [Android](https://developers.moengage.com/hc/en-us/categories/360006147431-Android-SDK), [iOS](https://developers.moengage.com/hc/en-us/articles/4403900743828-SDK-Integration), or [React Native](https://developers.moengage.com/hc/en-us/articles/22105190881044-Getting-Started-with-React-Native-SDK#h_01HEJAHP5W49AASNSHF5614AHP) Quick Start).

### Minimum Supported Versions

| Platform         | Environment                                                       | Minimum Dependencies                                                                                                                                                                                        |
| ---------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Flutter**      | <p>Dart <code>>=3.3.0</code><br>Flutter <code>>=3.20.0</code></p> | <p><code>digia\_engage: ^1.1.0</code><br><code>digia\_moengage\_plugin: ^1.0.0-beta.3</code><br><code>moengage\_flutter: ^10.5.0</code></p>                                                                 |
| **Android**      | `minSdk 24`                                                       | <p><code>tech.digia:engage:1.0.0-beta.03</code><br><code>tech.digia:engage-moengage:1.0.0-beta.03</code><br><code>com.moengage:moe-android-sdk:14.06.00</code><br><code>com.moengage:inapp:9.9.1</code></p> |
| **iOS (Swift)**  | iOS `16+`                                                         | <p><code>DigiaEngage: 1.0.0-beta.1</code><br><code>DigiaMoEngage: 1.0.0-beta.1</code></p>                                                                                                                   |
| **React Native** | React Native `0.73+`                                              | <p><code>@digia-engage/core: 1.0.0-beta.5</code><br><code>@digia-engage/moengage: 1.0.0-beta.2</code><br><code>react-native-moengage: installed</code></p>                                                  |

***

## 2. Install

> **Note:** We assume the core MoEngage SDK is already installed and initialized as part of your standard app setup (see [Prerequisites](#1-prerequisites)). The snippets below only cover adding the Digia plugin packages.

{% tabs %}
{% tab title="Flutter" %}
Add the Digia packages using the `flutter pub add` command:

```bash
flutter pub add digia_engage digia_moengage_plugin
```

{% endtab %}

{% tab title="Android" %}
Add dependencies in app `build.gradle.kts`:

```kotlin
dependencies {
  implementation("tech.digia:engage:1.0.0-beta.03")
  implementation("tech.digia:engage-moengage:1.0.0-beta.03")
}
```

Sync the project (Gradle sync).
{% endtab %}

{% tab title="iOS (Swift)" %}
Add packages using **Xcode → File → Add Package Dependencies** (or in `Package.swift`):

```swift
dependencies: [
    .package(url: "https://github.com/Digia-Technology-Private-Limited/digia_engage_iOS.git", exact: "1.0.0-beta.1"),
    .package(url: "https://github.com/Digia-Technology-Private-Limited/digia_moengage_iOS.git", exact: "1.0.0-beta.1"),
],
```

Then add these products to your app target dependencies:

* `DigiaEngage`
* `DigiaMoEngage`
  {% endtab %}

{% tab title="React Native" %}
Install the Digia packages:

```bash
npm install @digia-engage/core@1.0.0-beta.5 @digia-engage/moengage@1.0.0-beta.2
```

{% endtab %}
{% endtabs %}

***

## 3. Initialize Digia with MoEngage

Initialize Digia **after** the MoEngage SDK and **before** plugin registration.

{% tabs %}
{% tab title="Flutter" %}

```dart
import 'package:digia_moengage_plugin/digia_moengage_plugin.dart';
import 'package:digia_engage/digia_engage.dart';
import 'package:moengage_flutter/moengage_flutter.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 1. MoEngage SDK — initialise activates the native SDK already configured as a prerequisite.
  final moEngage = MoEngageFlutter('YOUR_MOENGAGE_APP_ID');
  moEngage.initialise();

  // 2. Initialize Digia before registering any CEP plugin.
  await Digia.initialize(
    DigiaConfig(apiKey: 'YOUR_ACCESS_KEY'),
  );

  // 3. Register the Digia MoEngage plugin.
  Digia.register(DigiaMoEngagePlugin(instance: moEngage));
  runApp(const MyApp());
}
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import android.app.Application
import com.digia.engage.Digia
import com.digia.engage.DigiaConfig
import com.digia.engage.moengage.DigiaMoEngagePlugin

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // 1. MoEngage SDK — initialized as a prerequisite.
        // MoEngage.initialiseDefaultInstance(moEngage)

        // 2. Initialize Digia before registering any CEP plugin.
        Digia.initialize(
            context = applicationContext,
            config = DigiaConfig(apiKey = "YOUR_ACCESS_KEY"),
        )

        // 3. Register the Digia MoEngage plugin. Context is required to resolve the MoEngage instance.
        Digia.register(DigiaMoEngagePlugin(applicationContext))
    }
}
```

{% endtab %}

{% tab title="iOS (Swift)" %}

```swift
import SwiftUI
import DigiaEngage
import DigiaMoEngage

@main
struct MyApp: App {
    init() {
        // 1. MoEngage SDK — initialized as a prerequisite.
        // MoEngage.sharedInstance.initializeDefaultInstance(...)

        // 2. Initialize Digia before registering any CEP plugin.
        Task {
            do {
                try await Digia.initialize(DigiaConfig(apiKey: "YOUR_ACCESS_KEY"))

                // 3. Register the Digia MoEngage plugin.
                Digia.register(DigiaMoEngagePlugin())
            } catch { }
        }
    }

    var body: some Scene {
        WindowGroup {
            RootView()
        }
    }
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import { useEffect } from 'react';
import ReactMoE from 'react-native-moengage';
import { Digia } from '@digia-engage/core';
import { DigiaMoEngagePlugin, createMoEngageClient } from '@digia-engage/moengage';

export function RootApp() {
  useEffect(() => {
    (async () => {
      // 1. MoEngage SDK — activate the JS bridge.
      ReactMoE.initialize('YOUR_MOENGAGE_WORKSPACE_ID');

      // 2. Initialize Digia before registering any CEP plugin.
      await Digia.initialize({
        apiKey: 'YOUR_ACCESS_KEY',
      });

      // 3. Register the Digia MoEngage plugin.
      Digia.register(
        new DigiaMoEngagePlugin({
          moEngage: createMoEngageClient(ReactMoE),
        })
      );
    })().catch(console.error);
  }, []);

  return <AppNavigator />;
}
```

{% endtab %}
{% endtabs %}

***

## 4. How Digia Maps to MoEngage Campaigns

| Experience Type | Digia Component | MoEngage Campaign Type | Description                                                                                               |
| --------------- | --------------- | ---------------------- | --------------------------------------------------------------------------------------------------------- |
| **Nudge**       | `DigiaHost`     | Self-Handled In-App    | Receives the campaign payload and renders overlay experiences (bottom sheets, dialogs) above app content. |
| **Inline**      | `DigiaSlot`     | Self-Handled In-App    | Receives placement key/value pairs and renders inline content (banners, cards) within the app layout.     |

{% @mermaid/diagram content="flowchart TD
Trigger\[MoEngage Campaign Trigger]
SDK\[MoEngage SDK]
Plugin\[Digia MoEngage Plugin]
Runtime\[digia\_engage runtime]
UI\[Campaign UI<br>native widgets from Digia Studio]

```
Trigger --> SDK
SDK -- "Self-handled in-app callback" --> Plugin
Plugin -- "maps payload -> InAppPayload" --> Runtime
Runtime -- "SHOW_BOTTOM_SHEET / SHOW_DIALOG<br>-> DigiaHost renders overlay" --> UI
Runtime -- "SHOW_INLINE<br>-> DigiaSlot renders inline" --> UI" %}
```

***

## 5. Setting Up Nudges

### Self-Handled In-App Campaigns: What They Are and Why They're Needed

MoEngage supports a delivery mode called **Self-Handled In-App Campaigns** — instead of MoEngage rendering its own campaign UI, the SDK delivers the campaign payload to your app code. The Digia MoEngage plugin registers a self-handled in-app listener that intercepts this payload, maps it to a `SHOW_BOTTOM_SHEET` or `SHOW_DIALOG` command, and delegates rendering to Digia's runtime. **Without setting the campaign template type to Self Handled in the MoEngage dashboard, the payload will not be delivered to the plugin.**

### Self-Handled In-App Campaigns: Set Up in Dashboard

No device-side sync is required — the plugin responds automatically once registered. Configure your campaign in the MoEngage dashboard:

1. Log in to the **MoEngage dashboard** and go to **Engage → In-App (NATIV)**.
2. Click **Create Campaign** and give it a name.
3. Set the **Template type** to **Self Handled**.
4. Configure the event trigger, audience, and schedule as required.
5. In the **Campaign data / Key-Value Pairs** field, enter the Digia payload JSON (see [Trigger a Nudge from MoEngage](#trigger-a-nudge-from-moengage) below).

See [MoEngage Self-Handled In-App](https://help.moengage.com/hc/en-us/articles/360051330591-Self-Handled-In-App-Template#h_01HP6KGBAVZDEV75BEFKRZ2M7R).

### Add the Nudge Container

Wrap your app root so overlay campaigns can render above app content.

{% tabs %}
{% tab title="Flutter" %}

```dart
import 'package:digia_engage/digia_engage.dart';
import 'package:flutter/material.dart';

MaterialApp(
  navigatorKey: DigiaHost.navigatorKey,
  navigatorObservers: [DigiaNavigatorObserver()],
  builder: (context, child) => DigiaHost(
    child: child!,
  ),
  home: const HomeScreen(),
)
```

{% endtab %}

{% tab title="Android (Jetpack Compose)" %}

```kotlin
import com.digia.engage.DigiaHost

DigiaHost {
    AppNavHost()
}
```

{% endtab %}

{% tab title="Android (XML Layout)" %}
For XML-based Android layouts, use `DigiaHostView` as a full-screen overlay in your root layout. This is the View-system wrapper around `DigiaHost`, so you do not need Compose code in your `Activity` or `Fragment`.

```xml
<FrameLayout
    android:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Your normal views / fragments -->

    <!-- Must be the last child so it draws on top -->
    <com.digia.engage.DigiaHostView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>
```

Or programmatically in your Activity:

```kotlin
import com.digia.engage.DigiaHostView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    val rootLayout = findViewById<FrameLayout>(R.id.root_layout)
    val digiaHost = DigiaHostView(this)
    rootLayout.addView(
        digiaHost,
        FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.MATCH_PARENT,
        )
    )
}
```

{% endtab %}

{% tab title="iOS (Swift)" %}

```swift
import SwiftUI
import DigiaEngage

struct RootContainerView: View {
    var body: some View {
        DigiaHost {
            AppRootView()
        }
    }
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { DigiaHostView } from '@digia-engage/core';
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <View style={styles.root}>
      {/* Host overlay for bottom sheets/dialogs above the app UI */}
      <DigiaHostView style={StyleSheet.absoluteFill} />
      <Stack />
    </View>
  );
}

const styles = StyleSheet.create({
  root: { flex: 1 },
});
```

{% endtab %}
{% endtabs %}

### Trigger a Nudge from MoEngage

Create a Self-Handled in-app campaign in MoEngage. In the campaign data payload, fill in the following fields:

| Field     | Required | Example value         | Description                                                                                                |
| --------- | -------- | --------------------- | ---------------------------------------------------------------------------------------------------------- |
| `command` | Yes      | `SHOW_BOTTOM_SHEET`   | `SHOW_BOTTOM_SHEET` or `SHOW_DIALOG`.                                                                      |
| `viewId`  | Yes      | `promo_offer_sheet`   | Digia page slug. See [Finding Slugs](https://docs.digia.tech/studio-workspace/builder-tool/finding-slugs). |
| `args`    | No       | `{"coupon":"SAVE20"}` | Enter as a raw JSON string in the text field. Available in Digia page logic at runtime.                    |

> **`args` format:** Enter the value as plain JSON text directly in the field — e.g., `{"coupon":"SAVE20"}`. Do not wrap it in outer quotes. The plugin JSON-decodes the string automatically.

***

## 6. Setting Up Inline Widgets

`DigiaSlot` is a composable/widget that renders Digia-powered content inline within your screen layout. Each slot is identified by a `placementKey` — a string that must match the `placementId` in the MoEngage campaign payload. When a Self-Handled in-app campaign with `SHOW_INLINE` is active, Digia resolves the component to display for each placement key and renders it inside the slot. If no campaign is active for a slot, it collapses to zero height.

### Add an Inline Slot

Place `DigiaSlot` where you want Self-Handled in-app inline content rendered.

{% tabs %}
{% tab title="Flutter" %}

```dart
import 'package:digia_engage/digia_engage.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: ListView(
        children: const [
          // Renders a Digia-powered banner campaign at the top of the feed.
          // placementKey must match the placementId in the MoEngage campaign payload.
          DigiaSlot('home_hero_banner'),
          SizedBox(height: 16),
          ProductCarousel(),
          SizedBox(height: 16),
          // Renders an inline offer card between content sections.
          DigiaSlot('product_offers'),
          SizedBox(height: 16),
          RecommendationList(),
        ],
      ),
    );
  }
}
```

{% endtab %}

{% tab title="Android (Jetpack Compose)" %}

```kotlin
import com.digia.engage.DigiaSlot

// placementKey must match placementId in MoEngage campaign payload
Column {
    DigiaSlot(placementKey = "home_hero_banner")
    DigiaSlot(placementKey = "product_offers")
}
```

{% endtab %}

{% tab title="Android (XML Layout)" %}
For View/XML layouts, use `DigiaSlotView`. It wraps the Compose `DigiaSlot` API and reads `app:placementKey` from XML.

```xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <com.digia.engage.DigiaSlotView
        android:id="@+id/homeHeroBanner"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:placementKey="home_hero_banner" />

    <com.digia.engage.DigiaSlotView
        android:id="@+id/productOffers"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:placementKey="product_offers" />

</LinearLayout>
```

Or set the placement programmatically after inflation:

```kotlin
import com.digia.engage.DigiaSlotView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_home)

    findViewById<DigiaSlotView>(R.id.homeHeroBanner).placementKey = "home_hero_banner"
    findViewById<DigiaSlotView>(R.id.productOffers).placementKey = "product_offers"
}
```

`DigiaSlotView` requires a `DigiaHostView` (or a Compose `DigiaHost`) in the same window so the Digia rendering engine is already mounted before the slot renders.
{% endtab %}

{% tab title="iOS (Swift)" %}

```swift
import SwiftUI
import DigiaEngage

struct HomeScreen: View {
    var body: some View {
        ScrollView {
            VStack(spacing: 16) {
                DigiaSlot(placementKey: "home_hero_banner")
                ProductCarousel()
                DigiaSlot(placementKey: "product_offers")
                RecommendationList()
            }
            .padding()
        }
    }
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import React from 'react';
import { ScrollView } from 'react-native';
import { DigiaSlotView } from '@digia-engage/core';

export function HomeScreen() {
  return (
    <ScrollView>
      <DigiaSlotView
        placementKey="home_hero_banner"
        style={{ width: '100%', height: 180 }}
      />

      <ProductCarousel />

      <DigiaSlotView
        placementKey="product_offers"
        style={{ width: '100%', height: 140 }}
      />

      <RecommendationList />
    </ScrollView>
  );
}
```

{% endtab %}
{% endtabs %}

### Serve Inline Content from MoEngage

For Self-Handled in-app campaigns, set the payload `type` to `inline` and provide the `placementKey` and `viewId`:

```json
{
  "type": "inline",
  "placementKey": "home_hero_banner",
  "viewId": "home_hero_banner-v2N8"
}
```

| Field          | Required | Description                                                                                                                             |
| -------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `type`         | Yes      | Must be `inline` for inline slots.                                                                                                      |
| `placementKey` | Yes      | Must match the `DigiaSlot` / `DigiaSlotView` placement key in your app code.                                                            |
| `viewId`       | Yes      | Digia component or page slug. See [Finding Slugs](https://docs.digia.tech/studio-workspace/builder-tool/finding-slugs) for slug lookup. |

See [Finding Slugs](https://docs.digia.tech/studio-workspace/builder-tool/finding-slugs) for slug lookup.

***

## 7. Test Your Integration

Follow these steps to verify end-to-end functionality before releasing:

1. **Verify initialization order** — `Digia.initialize` completes, then `Digia.register(DigiaMoEngagePlugin(...))`, before `runApp` / first activity.
2. **Verify host placement** — `DigiaHost` must be in `MaterialApp.builder` (Flutter), the root Composable (Android Compose), or the root SwiftUI wrapper (iOS). For Android View/XML apps, `DigiaHostView` should be mounted once as the last full-screen child of the root `ViewGroup`. For React Native, `DigiaHostView` is to be used.
3. **Set campaign to Self Handled** — ensure the MoEngage in-app campaign template type is **Self Handled** in the MoEngage dashboard (see [Self-Handled In-App Campaigns: Set Up in Dashboard](#self-handled-in-app-campaigns-set-up-in-dashboard)).
4. **Create a test campaign** — create a Self-Handled in-app campaign with a known `viewId` and trigger it immediately for your test device.
5. **Verify inline slots** — place `DigiaSlot` / `DigiaSlotView` on a visible screen, create a Self-Handled in-app campaign with `SHOW_INLINE` and a matching `placementId`, and confirm content renders.
6. **Verify screen tracking** — navigate between screens and confirm that screen-triggered campaigns fire on the correct screen (use `DigiaNavigatorObserver` on Flutter, `Digia.setCurrentScreen(...)` or `digiaScreen("...")` in Android View/XML apps, route/screen change hooks calling `Digia.setCurrentScreen(...)` on Swift, and navigation listeners calling `Digia.setCurrentScreen(...)` on React Native).

### Health Check

Use `plugin.healthCheck()` to verify plugin wiring. The report shape is platform-specific, but always includes `isHealthy` plus diagnostic metadata.

{% tabs %}
{% tab title="Flutter" %}

```dart
final moEngage = MoEngageFlutter('YOUR_MOENGAGE_APP_ID');
moEngage.initialise();

final plugin = DigiaMoEngagePlugin(instance: moEngage);
Digia.register(plugin);

// Later, for testing:
final report = plugin.healthCheck();
if (!report.isHealthy) {
  debugPrint('Plugin issue: ${report.issue}');
  debugPrint('Resolution: ${report.resolution}');
}
```

{% endtab %}

{% tab title="Android (Jetpack Compose)" %}

```kotlin
val plugin = DigiaMoEngagePlugin(applicationContext)
Digia.register(plugin)

// Later, for testing:
val report = plugin.healthCheck()
if (!report.isHealthy) {
  Log.w("Digia", "Plugin issue: ${report.issue} - ${report.resolution}")
}
```

{% endtab %}

{% tab title="iOS (Swift)" %}

```swift
let plugin = DigiaMoEngagePlugin()
Digia.register(plugin)

// Later, for testing:
let report = plugin.healthCheck()
if !report.isHealthy {
    print("Plugin issue: \(report.issue)")
    print("Resolution: \(report.resolution)")
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import MoEngage from 'react-native-moengage';
import { Digia } from '@digia-engage/core';
import { DigiaMoEngagePlugin, createMoEngageClient } from '@digia-engage/moengage';

const plugin = new DigiaMoEngagePlugin({
  moEngage: createMoEngageClient(MoEngage),
});

Digia.register(plugin);

// Later, for testing:
const report = plugin.healthCheck();
if (!report.isHealthy) {
  console.warn('Plugin health check failed', report.metadata);
}
```

{% endtab %}
{% endtabs %}

***

## 8. Troubleshooting

Reference open-source example apps for integration patterns:

* [medihub\_flutter](https://github.com/Digia-Technology-Private-Limited/medihub_flutter)
* [medihub\_android](https://github.com/Digia-Technology-Private-Limited/medihub_android)
* [medihub\_swift](https://github.com/Digia-Technology-Private-Limited/medihub_swift)
* [medihub\_rn](https://github.com/Digia-Technology-Private-Limited/medihub_rn)

### Campaign not rendering

* Confirm initialization order — `Digia.initialize(...)` then `Digia.register(DigiaMoEngagePlugin(...))`.
* Ensure the MoEngage campaign template type is set to **Self Handled** in the MoEngage dashboard.
* **iOS (Swift)**: Confirm `MoEngage.sharedInstance.initializeDefaultInstance(...)` runs at app start and `Info.plist` includes `MOEnvType`.
* **React Native**: Confirm `Digia.initialize(...)` and `Digia.register(new DigiaMoEngagePlugin(...))` are called once during app startup.
* Ensure `DigiaHost` is mounted in `MaterialApp.builder` (Flutter), the root Composable (Android Compose), or `DigiaHostView` is mounted as the last full-screen child in your Android View/XML root layout.
* **React Native**: Ensure `DigiaHostView` is mounted once at app root and `app.json` contains MoEngage plugin credentials.
* Check `viewId` exactly matches the published Digia page slug (case-sensitive). See [Finding Slugs](https://docs.digia.tech/studio-workspace/builder-tool/finding-slugs).
* Verify campaign eligibility and trigger conditions in the MoEngage dashboard.

### Inline content not showing

* Confirm Self-Handled in-app payload includes `"type": "inline"` and a `placementKey` value.
* Ensure `placementKey` in payload matches `DigiaSlot('placement_key')` or `DigiaSlotView app:placementKey` exactly (case-sensitive).
* Verify the slot exists on the currently visible screen.
* **Android XML**: Ensure a `DigiaHostView` is mounted in the same window before `DigiaSlotView` renders.
* **React Native**: Ensure `DigiaSlotView` has an explicit height/size in `style`, otherwise nothing is visible.

### Screen-triggered campaign not firing

* Add `DigiaNavigatorObserver()` to `navigatorObservers` (Flutter).
* Call `Digia.setCurrentScreen(...)` on navigation changes (Android Compose: `navController.addOnDestinationChangedListener`).
* **Android XML / Views**: Call `digiaScreen("screen_name")` from `Activity.onResume()` or `Fragment.onResume()`.
* For unnamed routes, call `Digia.setCurrentScreen('screen_name')` manually.
* **iOS (Swift)**: On tab/route changes, call `Digia.setCurrentScreen("screen_name")` from your navigation layer.
* **React Native**: Wire navigation change events (React Navigation / Expo Router) to `Digia.setCurrentScreen(routeName)`.

### MoEngage SDK not initialized (Android)

* Ensure `MoEngage.initialise(moEngage)` is called in `Application.onCreate()` before `Digia.register(...)`.
* Verify MoEngage credentials are correctly configured per [MoEngage Android Quick Start](https://developers.moengage.com/hc/en-us/categories/360006147431-Android-SDK).

***

## Official MoEngage References

* [Flutter SDK](https://developers.moengage.com/hc/en-us/articles/20661421128084-Getting-Started-with-Flutter-SDK)
* [Android Quick Start](https://developers.moengage.com/hc/en-us/categories/360006147431-Android-SDK)
* [iOS SDK Integration](https://developers.moengage.com/hc/en-us/categories/360006471532-iOS-SDK)
* [React Native Quick Start Guide](https://developers.moengage.com/hc/en-us/categories/4404199274900-React-Native-SDK)
