Digia MoEngage Integration
The Digia MoEngage plugin intercepts MoEngage Self-Handled In-App campaign payloads and pipes them directly into Digia's rendering engine. Each MoEngage campaign carries a single digia_campaign_key that maps to a campaign you design in the Digia Engage Dashboard. When the campaign triggers, the plugin resolves that key against the campaigns Digia pre-fetched at startup and instantly renders a 100% native experience on the device—no WebViews required. Supported experience types include bottom sheets, dialogs, inline banners, surveys, tooltips, and spotlights.
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.
Prerequisites
Before integrating, ensure you have:
- Digia Access Key: Log in to the Digia Engage Dashboard, 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, Android, iOS, or React Native Quick Start).
Minimum Supported Versions
- React Native
- Flutter
- Android
- iOS (Swift)
- Environment: React Native
0.83+, React19.2+ - Digia packages:
@digia-engage/core,@digia-engage/moengage - MoEngage SDK:
react-native-moengage
- Environment: Dart
3.3+, Flutter3.35+ - Digia packages:
digia_engage,digia_moengage_plugin - MoEngage SDK:
moengage_flutter
- Environment:
minSdk 24 - Digia packages:
tech.digia:engage,tech.digia:engage-moengage - MoEngage SDK:
com.moengage:moe-android-sdk
- Environment: iOS
16+ - Digia packages:
DigiaEngage,DigiaMoEngage - MoEngage SDK: MoEngage iOS SDK
Install
Note: We assume the core MoEngage SDK is already installed and initialized as part of your standard app setup (see Prerequisites). The snippets below only cover adding the Digia plugin packages.
- React Native
- Flutter
- Android
- iOS (Swift)
Install the Digia packages:
npm install @digia-engage/core@2.22.0 @digia-engage/moengage@1.1.3
Add the Digia packages using the flutter pub add command:
flutter pub add digia_engage:1.19.0 digia_moengage_plugin:1.0.1
Add dependencies in app build.gradle.kts (use the latest versions from Maven Central):
dependencies {
implementation("tech.digia:engage:2.17.0")
implementation("tech.digia:engage-moengage:1.0.0-beta.04")
}
Sync the project (Gradle sync).
Add packages using Xcode → File → Add Package Dependencies and choose Up to Next Major Version — or in Package.swift, use the latest versions from Swift Package Index:
dependencies: [
.package(url: "https://github.com/Digia-Technology-Private-Limited/digia_engage_iOS.git", from: "3.14.0"),
.package(url: "https://github.com/Digia-Technology-Private-Limited/digia_moengage_iOS.git", from: "1.0.0-beta.2"),
],
Then add these products to your app target dependencies:
DigiaEngageDigiaMoEngage
Initialize Digia with MoEngage
Initialize Digia after the MoEngage SDK and before plugin registration.
- React Native
- Flutter
- Android
- iOS (Swift)
import { useEffect } from 'react';
import ReactMoE from 'react-native-moengage';
import { Digia } from '@digia-engage/core';
import { DigiaMoEngagePlugin } 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. Pass the ReactMoE module directly.
Digia.register(new DigiaMoEngagePlugin({ moEngage: ReactMoE }));
})().catch(console.error);
}, []);
return <AppNavigator />;
}
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(MoEngagePlugin(instance: moEngage));
runApp(const MyApp());
}
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))
}
}
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()
}
}
}
How Digia Maps to MoEngage Campaigns
If you haven't read How It Works in the overview, start there. The section below covers only what is MoEngage-specific.
In short: MoEngage decides who sees a campaign and when. Digia decides what is rendered. The two are linked by a digia_campaign_key you set in the MoEngage dashboard — the Digia plugin reads that key, resolves it against its local cache, and renders the right experience natively.
The table below shows how each Digia experience type maps to a MoEngage campaign type and which SDK component handles it on the app side:
| Experience Type | Digia Component | MoEngage Campaign Type | Description |
|---|---|---|---|
| Nudge | DigiaHost | Self-Handled In-App | Renders overlay experiences (bottom sheets, dialogs) above app content. |
| Guide | DigiaAnchor + DigiaHost | Self-Handled In-App | Step-by-step tooltip/spotlight flows anchored to specific UI elements. Each step targets a registered anchorKey. |
| Survey | DigiaHost | Self-Handled In-App | Multi-step survey flows rendered as overlays. |
| Inline | DigiaSlot | Self-Handled In-App | Renders inline content (banners, cards) within the app layout at a matching placement. |
Here is the end-to-end flow for a Self-Handled In-App campaign (Nudge, Guide, Survey, or Inline):
The Campaign Contract
Whatever the experience type, a Digia-powered MoEngage campaign carries the same payload in its Campaign data / Key-Value Pairs field — a single JSON object:
{
"digia_campaign_key": "promo_offer_sheet",
"variables": {
"coupon": "SAVE20",
"offer_title": "Limited Offer"
}
}
digia_campaign_key(required) — the key of the Digia campaign to render. This alone determines the experience type (nudge, guide, survey, or inline) and its design; nothing about the UI lives in the MoEngage payload.variables(optional) — a JSON object of runtime values interpolated into the campaign at render time.
Every experience type — nudge, guide, survey, and inline — is delivered through the same Self-Handled In-App campaign with this same payload. The per-experience sections below show it in context.
Self-Handled In-App Campaigns
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, extracts the digia_campaign_key, resolves it against the Digia campaigns pre-fetched at startup, 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.
No device-side sync is required — the plugin responds automatically once registered. Configure your campaign in the MoEngage dashboard:
- Log in to the MoEngage dashboard and go to Engage → In-App (NATIV).
- Click Create Campaign and give it a name.
- Set the Template type to Self Handled.
- Configure the event trigger, audience, and schedule as required.
- In the Campaign data / Key-Value Pairs field, add a key named
digia_campaign_keywith the Digia campaign key copied from your Digia dashboard.
See MoEngage Self-Handled In-App.
Setting Up Nudges
Add the Nudge Container
Wrap your app root so overlay campaigns can render above app content.
- React Native
- Flutter
- Android
- iOS (Swift)
Mount <DigiaHost /> once at your app root.
import React from 'react';
import { View } from 'react-native';
import { DigiaHost } from '@digia-engage/core';
export default function RootLayout() {
return (
<View style={{ flex: 1 }}>
<DigiaHost />
<AppNavigator />
</View>
);
}
import 'package:digia_engage/digia_engage.dart';
import 'package:flutter/material.dart';
MaterialApp(
navigatorObservers: [DigiaNavigatorObserver()],
builder: (context, child) => DigiaHost(child: child!),
home: const HomeScreen(),
)
Jetpack Compose
import com.digia.engage.DigiaHost
DigiaHost {
AppNavHost()
}
import SwiftUI
import DigiaEngage
struct RootContainerView: View {
var body: some View {
DigiaHost {
AppRootView()
}
}
}
Trigger a Nudge from MoEngage
Create a Self-Handled In-App campaign in MoEngage. In the Campaign data / Key-Value Pairs field, provide the digia_campaign_key that links to your Digia campaign:
{
"digia_campaign_key": "promo_offer_sheet"
}
| Field | Required | Example value | Description |
|---|---|---|---|
digia_campaign_key | Yes | promo_offer_sheet | The Digia campaign key copied from your Digia dashboard. Its type (nudge / guide / survey / inline) and design come from Digia, not the payload. |
variables | No | {"coupon":"SAVE20"} | Optional JSON map of runtime variables interpolated into the campaign at render time. |
Linking: In the Digia dashboard, copy the Digia campaign key assigned to your campaign. In the MoEngage Self-Handled In-App campaign's Key-Value Pairs, add a key named
digia_campaign_keywith that value. If the values differ, the plugin cannot resolve the campaign and nothing renders.
variablesformat: 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 payload automatically.
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. When a Self-Handled In-App campaign whose digia_campaign_key maps to an inline Digia campaign triggers, Digia renders that campaign into the slot whose placementKey matches the slot key configured on the campaign in the Digia dashboard. If no campaign is active for a slot, it collapses to zero height.
Add an Inline Slot
Place DigiaSlot where you want inline content rendered.
- React Native
- Flutter
- Android
- iOS (Swift)
import React from 'react';
import { ScrollView } from 'react-native';
import { DigiaSlotView } from '@digia-engage/core';
export function HomeScreen() {
return (
<ScrollView>
{/* Auto-sizes to match native content height. Pass style={{ height: N }} to pin a fixed height. */}
<DigiaSlotView placementKey="home_hero_banner" />
<ProductCarousel />
<DigiaSlotView placementKey="product_offers" />
<RecommendationList />
</ScrollView>
);
}
import 'package:digia_engage/digia_engage.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: ListView(
children: const [
DigiaSlot('home_hero_banner'),
SizedBox(height: 16),
ProductCarousel(),
SizedBox(height: 16),
DigiaSlot('product_offers'),
SizedBox(height: 16),
RecommendationList(),
],
),
);
}
}
Jetpack Compose
import com.digia.engage.DigiaSlot
Column {
DigiaSlot(placementKey = "home_hero_banner")
DigiaSlot(placementKey = "product_offers")
}
XML Layout
For View/XML layouts, use DigiaSlotView. It wraps the Compose DigiaSlot API and reads app:placementKey from 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:
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 DigiaHost to be mounted in the same window so the Digia rendering engine is already mounted before the slot renders.
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()
}
}
}
Serve Inline Content from MoEngage
Inline campaigns are delivered the same way as nudges — through a Self-Handled In-App campaign carrying a digia_campaign_key. Build the inline campaign in the Digia dashboard (it defines which slot / placementKey it targets), then set digia_campaign_key to the Digia campaign key from that campaign:
{
"digia_campaign_key": "home_hero_banner_campaign"
}
| Field | Required | Description |
|---|---|---|
digia_campaign_key | Yes | The Digia campaign key of an inline campaign copied from your Digia dashboard. The campaign defines which slot key it renders into. |
The app-side DigiaSlot / DigiaSlotView placementKey must match the slot key configured on that campaign in the Digia dashboard.
Inline content stays loaded once a campaign renders it — it doesn't clear when the user's context changes. To clear it (for example on logout), see Managing Inline Content.
Setting Up Guides
DigiaAnchor registers a UI element as a named anchor for tooltip and spotlight Guide campaigns. When a Guide campaign runs, the SDK looks up the anchorKey to position the tooltip bubble or spotlight cutout relative to that element.
Wrap any element you want to anchor and give it a unique anchorKey. The key must match exactly what is configured for that step in the Digia dashboard Guide campaign.
- React Native
- Flutter
- Android
- iOS (Swift)
import { DigiaAnchorView } from '@digia-engage/core';
// Anywhere in your screen component:
<DigiaAnchorView anchorKey="buy_now_button">
<BuyNowButton />
</DigiaAnchorView>
import 'package:digia_engage/digia_engage.dart';
// Anywhere in your widget tree:
DigiaAnchor(
anchorKey: 'buy_now_button',
child: BuyNowButton(),
)
Jetpack Compose
import com.digia.engage.DigiaAnchor
// Anywhere in your composable:
DigiaAnchor(anchorKey = "buy_now_button") {
BuyNowButton()
}
XML Layout
<com.digia.engage.DigiaAnchorView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:anchorKey="buy_now_button">
<!-- Your view -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Buy Now" />
</com.digia.engage.DigiaAnchorView>
import DigiaEngage
// Anywhere in your view hierarchy:
DigiaAnchor(anchorKey: "buy_now_button") {
BuyNowButton()
}
Note: If the anchor is not mounted when a Guide campaign fires, the SDK logs an
anchor_not_on_screenhealth event and skips that step. Ensure the anchor is on screen before navigating to the Guide step.
Link the MoEngage Campaign to Digia
To connect a MoEngage campaign to your Digia Guide, copy the Digia campaign key assigned to your Guide campaign in the Digia dashboard. Then, in the MoEngage Self-Handled In-App campaign's Key-Value Pairs, add a key named digia_campaign_key with that value:
{
"digia_campaign_key": "onboarding_tour"
}
Note: The
digia_campaign_keyvalue must exactly match the Digia campaign key from the dashboard. If they differ, the plugin cannot resolve the campaign and nothing renders.
Setting Up Surveys
Surveys are multi-step questionnaire flows you design in the Digia dashboard and render as overlays in the nudge host — no extra app-side widget is required beyond the nudge container. A survey is just another campaign type: create it in Digia, then trigger it from MoEngage by referencing its Digia campaign key via digia_campaign_key, exactly like a nudge.
- Build the survey campaign in the Digia Engage Dashboard and copy its Digia campaign key.
- Ensure your app mounts the nudge container —
DigiaHostat the app root (all platforms). - Create a MoEngage Self-Handled In-App campaign and add a
digia_campaign_keyKey-Value Pair set to the survey's Digia campaign key.
{
"digia_campaign_key": "nps_q3_survey"
}
The survey renders over your app content and reports completion back through the plugin's analytics events.
Test Your Integration
Follow these steps to verify end-to-end functionality before releasing:
- Verify initialization order —
Digia.initializecompletes, thenDigia.register(...)with the MoEngage plugin (MoEngagePluginon Flutter,DigiaMoEngagePluginon React Native), beforerunApp/ first activity. - Verify host placement —
DigiaHostmust be inMaterialApp.builder(Flutter), the root Composable (Android Compose), or the root SwiftUI wrapper (iOS). For React Native, mount<DigiaHost />once at the app root. - 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).
- Create a test campaign — create a Self-Handled In-App campaign with a
digia_campaign_keypointing to a known Digia campaign and trigger it immediately for your test device. - Verify inline slots — place
DigiaSlot/DigiaSlotViewon a visible screen, trigger a Self-Handled In-App campaign whosedigia_campaign_keypoints to an inline Digia campaign targeting that slot, and confirm content renders. - Verify guides — register a
DigiaAnchor/DigiaAnchorViewwith ananchorKey, point a Guide campaign step at it, and confirm the tooltip/spotlight anchors correctly. - Verify screen tracking — navigate between screens and confirm that screen-triggered campaigns fire on the correct screen (use
DigiaNavigatorObserveron Flutter,Digia.setCurrentScreen(...)ordigiaScreen("...")in Android View/XML apps, route/screen change hooks callingDigia.setCurrentScreen(...)on Swift, and navigation listeners callingDigia.setCurrentScreen(...)on React Native). See Reporting the Current Screen for per-stack and per-router wiring, and Screen Targeting to scope campaigns to specific screens.
Troubleshooting
Campaign not rendering
- Confirm initialization order —
Digia.initialize(...)thenDigia.register(...)with the MoEngage plugin (MoEngagePluginon Flutter,DigiaMoEngagePluginon React Native). - 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 andInfo.plistincludesMOEnvType. - React Native: Confirm
Digia.initialize(...)andDigia.register(new DigiaMoEngagePlugin(...))are called once during app startup. - Ensure
DigiaHostis mounted at the app root. - React Native: Ensure
<DigiaHost />is mounted once at app root, and confirmDigia.initialize(...)completes beforeDigia.register(...). - Check
digia_campaign_keyexactly matches the Digia campaign key (case-sensitive). - Verify campaign eligibility and trigger conditions in the MoEngage dashboard.
Inline content not showing
- Confirm the Self-Handled In-App payload includes a
digia_campaign_keythat maps to an inline Digia campaign. - Ensure the campaign's slot key (configured in the Digia dashboard) matches
DigiaSlot('placement_key')orDigiaSlotView app:placementKeyexactly (case-sensitive). - Verify the slot exists on the currently visible screen.
- React Native:
DigiaSlotViewauto-sizes to match native content height. If it still appears collapsed, confirm the inline campaign is active and theplacementKeymatches. To pin a fixed height, passstyle={{ height: 180 }}.
Guide (tooltip / spotlight) not anchoring
- Ensure the element is wrapped in
DigiaAnchor/DigiaAnchorViewwith ananchorKeythat exactly matches the step configured in the Digia dashboard Guide campaign. - Confirm the anchor is mounted on screen when the campaign fires — if not, the SDK logs
anchor_not_on_screenand skips the step. - React Native: Confirm
<DigiaHost />is mounted at the app root.
Screen-triggered campaign not firing
- Add
DigiaNavigatorObserver()tonavigatorObservers(Flutter). - Call
Digia.setCurrentScreen(...)on navigation changes (Android Compose:navController.addOnDestinationChangedListener). - Android XML / Views: Call
digiaScreen("screen_name")fromActivity.onResume()orFragment.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 inApplication.onCreate()beforeDigia.register(...). - Verify MoEngage credentials are correctly configured per MoEngage Android Quick Start.