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 (including auto-tracked events), 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
let messages = AppDNA.inAppMessages
Module Methods
| Method | Signature | Description |
|---|
suppressDisplay | suppressDisplay(_ suppress: Bool) | Suppress or resume in-app messages |
setDelegate | setDelegate(_ delegate: AppDNAInAppMessageDelegate?) | Set a delegate for message callbacks |
Suppressing Messages
Suppress messages during critical flows like checkout or onboarding to avoid interrupting the user:
// Suppress during purchase flow
AppDNA.inAppMessages.suppressDisplay(true)
startPurchaseFlow()
// Resume after purchase completes
func purchaseDidComplete() {
AppDNA.inAppMessages.suppressDisplay(false)
}
AppDNAInAppMessageDelegate
Implement the delegate to respond to message lifecycle events:
protocol AppDNAInAppMessageDelegate {
func onMessageShown(messageId: String, trigger: String)
func onMessageAction(messageId: String, action: String, data: [String: Any]?)
func onMessageDismissed(messageId: String)
func shouldShowMessage(messageId: String) -> Bool
}
Example Implementation
class MessageHandler: AppDNAInAppMessageDelegate {
func onMessageShown(messageId: String, trigger: String) {
print("Message shown: \(messageId) (trigger: \(trigger))")
}
func onMessageAction(messageId: String, action: String, data: [String: Any]?) {
if let url = data?["url"] as? String {
// Handle deep link or URL action
navigate(to: url)
}
}
func onMessageDismissed(messageId: String) {
print("Message dismissed: \(messageId)")
}
func shouldShowMessage(messageId: String) -> Bool {
// Return false to prevent the message from being shown
return true
}
}
AppDNA.inAppMessages.setDelegate(MessageHandler())
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, SF Symbols, 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 AppDNASDK
class AppCoordinator: AppDNAInAppMessageDelegate {
func setup() {
AppDNA.inAppMessages.setDelegate(self)
}
func startOnboarding() {
// Suppress messages during onboarding
AppDNA.inAppMessages.suppressDisplay(true)
presentOnboardingFlow()
}
func onboardingDidFinish() {
// Resume messages after onboarding
AppDNA.inAppMessages.suppressDisplay(false)
}
// MARK: - AppDNAInAppMessageDelegate
func onMessageShown(messageId: String, trigger: String) {
// Optionally track in your own analytics
}
func onMessageAction(messageId: String, action: String, data: [String: Any]?) {
switch action {
case "deep_link":
if let url = data?["url"] as? String { navigate(to: url) }
case "dismiss":
break
default:
break
}
}
func onMessageDismissed(messageId: String) {
// Message closed
}
func shouldShowMessage(messageId: String) -> Bool {
return true
}
}
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.