In-app messages are configured in the AppDNA Console and displayed automatically by the SDK when trigger conditions are met. No code is required to show messages — the SDK evaluates triggers on every tracked event and presents the message if conditions match.
How It Works
- You create an in-app message in the Console with content, layout, and trigger rules.
- The message definition is synced to the SDK via the config bundle.
- On every
track() call, the SDK evaluates all active message triggers.
- If conditions match, the message is presented automatically.
In-app messages are fully server-driven. You can change the message content, trigger rules, and audience without an app update.
Message Types
| Type | Description |
|---|
banner | Small bar at the top or bottom of the screen |
modal | Centered overlay with a dimmed background |
fullscreen | Full-screen takeover |
tooltip | Small popup anchored to a UI element |
Triggers
Messages trigger based on events and optional conditions, configured in the Console:
- Event match — e.g., trigger on
workout_completed
- Property conditions — e.g.,
duration >= 30
- Frequency —
once, once_per_session, or every_time
- Delay — wait N seconds after the trigger event before showing
Module Access
val messages = AppDNA.inAppMessages
Module Methods
| Method | Signature | Description |
|---|
suppress | suppress() | Suppress all in-app messages |
unsuppress | unsuppress() | Resume showing in-app messages |
setDelegate | setDelegate(delegate: InAppMessageDelegate?) | Set a delegate for message callbacks |
Suppressing Messages
Suppress messages during critical flows like checkout or onboarding:
AppDNA.inAppMessages.suppress()
startPurchaseFlow()
// Resume after purchase completes
fun onPurchaseComplete() {
AppDNA.inAppMessages.unsuppress()
}
InAppMessageDelegate
AppDNA.inAppMessages.delegate = object : InAppMessageDelegate {
override fun onMessagePresented(messageId: String, messageType: String) {
println("Message shown: $messageId ($messageType)")
}
override fun onMessageAction(messageId: String, action: String, url: String?) {
url?.let { navigate(it) }
}
override fun onMessageDismissed(messageId: String) {
println("Message dismissed: $messageId")
}
}
In-app messages support rich media content configured in the Console:
- Lottie animations — animated hero images or backgrounds
- Video — inline video with optional autoplay and looping
- Icon buttons — CTA buttons with icon references (Lucide, Material, or emoji)
- Haptic feedback — triggered on message display or button taps
- Particle effects — confetti, sparkles, or other effects on message actions
- Blur backdrop — glassmorphism-style blurred background for modals
See the Rich Media guide for details on supported formats and configuration.
Auto-Tracked Events
| Event | Trigger |
|---|
message_presented | An in-app message is displayed |
message_action | User taps an action in the message |
message_dismissed | Message is closed |
Full Example
import ai.appdna.sdk.AppDNA
import ai.appdna.sdk.InAppMessageDelegate
class AppCoordinator : InAppMessageDelegate {
fun setup() {
AppDNA.inAppMessages.delegate = this
}
fun startOnboarding() {
AppDNA.inAppMessages.suppress()
presentOnboardingFlow()
}
fun onboardingDidFinish() {
AppDNA.inAppMessages.unsuppress()
}
override fun onMessagePresented(messageId: String, messageType: String) {
// Optionally track in your own analytics
}
override fun onMessageAction(messageId: String, action: String, url: String?) {
when (action) {
"deep_link" -> url?.let { navigate(it) }
"dismiss" -> { }
}
}
override fun onMessageDismissed(messageId: String) {
// Message closed
}
}
In-app messages are created in the Console under Engagement > In-App Messages. Design the message, set trigger rules, and publish. The SDK handles everything else.