Skip to main content
The Radar iOS SDK enables you to display rich in-app messages to users based on their location and behavior. These messages appear within your app, providing a native and non-intrusive way to engage users.

Overview

In-app messages support:
  • Location-triggered messaging: Show messages when users enter geofences or approach destinations
  • Rich content: Display titles, body text, images, and call-to-action buttons
  • Custom styling: Customize colors, fonts, and layout
  • Deep linking: Navigate users to specific screens in your app
  • Conversion tracking: Automatically track message displays, dismissals, and button clicks

Setup

The SDK automatically manages in-app messages when location events occur. No additional setup is required beyond initializing the SDK.
import RadarSDK

Radar.initialize(publishableKey: "YOUR_PUBLISHABLE_KEY")
In-app messages require iOS 13.0 or later and are available starting with SDK version 3.10+.

Configure messages in the dashboard

Create in-app messages in the Radar dashboard by adding message metadata to your geofences or campaigns:
{
  "title": {
    "text": "Welcome to Our Store!",
    "color": "#000000"
  },
  "body": {
    "text": "Check out our latest deals and save 20% today.",
    "color": "#666666"
  },
  "button": {
    "text": "View Deals",
    "color": "#FFFFFF",
    "backgroundColor": "#0066FF",
    "deepLink": "myapp://deals"
  },
  "image": {
    "name": "store-banner",
    "url": "https://example.com/images/store-banner.png"
  },
  "metadata": {
    "radar:campaignId": "store-entry-2024",
    "radar:campaignName": "Store Entry Campaign",
    "radar:geofenceId": "store-123"
  }
}

Message structure

An in-app message consists of:
PropertyTypeRequiredDescription
titleTextYesMessage title with text and color
bodyTextYesMessage body with text and color
buttonButtonNoOptional call-to-action button
imageImageNoOptional banner image
metadataDictionaryNoAdditional metadata for tracking

Text properties

struct Text {
    var text: String      // The text content
    var color: UIColor    // Hex color (e.g., "#000000")
}

Button properties

struct Button {
    var text: String              // Button label
    var color: UIColor            // Text color
    var backgroundColor: UIColor  // Button background color
    var deepLink: String?         // Optional deep link URL
}

Image properties

struct Image {
    var name: String    // Image identifier
    var url: String     // Image URL
}

Customize message presentation

Implement the RadarInAppMessageProtocol to customize message presentation:
import RadarSDK

@available(iOS 13.0, *)
class CustomInAppMessageDelegate: RadarInAppMessageDelegate {
    
    // Called when a new message is received
    override func onNewInAppMessage(_ message: RadarInAppMessage) {
        print("New in-app message received")
        
        // Automatically show the message
        Task { @MainActor in
            await RadarInAppMessageManager.shared.showInAppMessage(message)
        }
    }
    
    // Called when a message is dismissed
    override func onInAppMessageDismissed(_ message: RadarInAppMessage) {
        print("In-app message dismissed")
    }
    
    // Called when a button is clicked
    override func onInAppMessageButtonClicked(_ message: RadarInAppMessage) {
        print("In-app message button clicked")
        
        // Handle deep link
        if let button = (message as? RadarInAppMessage_Swift)?.button,
           let deepLink = button.deepLink,
           let url = URL(string: deepLink) {
            handleDeepLink(url)
        }
    }
    
    // Customize the message view
    override func createInAppMessageView(
        _ message: RadarInAppMessage,
        onDismiss: @escaping () -> Void,
        onInAppMessageClicked: @escaping () -> Void,
        completionHandler: @escaping (UIViewController) -> Void
    ) {
        // Return your custom view controller
        let customViewController = CustomMessageViewController(message: message)
        customViewController.onDismiss = onDismiss
        customViewController.onButtonClicked = onInAppMessageClicked
        
        completionHandler(customViewController)
    }
}

// Set the custom delegate
if #available(iOS 13.0, *) {
    Task { @MainActor in
        RadarInAppMessageManager.shared.setDelegate(CustomInAppMessageDelegate())
    }
}

Show messages programmatically

Manually display in-app messages:
import RadarSDK

@available(iOS 13.0, *)
func showMessage(_ message: RadarInAppMessage) {
    Task { @MainActor in
        await RadarInAppMessageManager.shared.showInAppMessage(message)
    }
}

Conversion tracking

The SDK automatically tracks in-app message conversions:
EventDescription
user.displayed_in_app_messageMessage was shown to the user
user.dismissed_in_app_messageUser dismissed the message
user.clicked_in_app_messageUser clicked the message button
Conversions include metadata:
  • displayDuration: How long the message was shown (seconds)
  • campaignId: Campaign identifier
  • campaignName: Campaign name
  • geofenceId: Triggering geofence ID
View conversion analytics in the Radar dashboard under Analytics > Conversions. Process deep links from message buttons:
func handleDeepLink(_ url: URL) {
    // Parse the URL and navigate
    if url.scheme == "myapp" {
        switch url.host {
        case "deals":
            showDealsScreen()
        case "product":
            if let productId = url.pathComponents.last {
                showProductDetails(productId)
            }
        default:
            break
        }
    }
}

Message display rules

The SDK follows these rules for displaying messages:
  1. Only one message is shown at a time
  2. New messages are ignored while a message is currently displayed
  3. Messages are shown on the app’s key window
  4. Messages are displayed with a semi-transparent background overlay
  5. Users can dismiss messages by tapping outside the message view

Best practices

Keep messages concise

Use short, actionable text that users can quickly read and understand.

Test on different devices

Verify messages display correctly on various screen sizes and iOS versions.

Use high-quality images

Optimize images for mobile and provide appropriate resolutions for retina displays.

Implement deep links

Always provide a button with a deep link to make messages actionable.

Example: Complete implementation

import RadarSDK
import UIKit

@available(iOS 13.0, *)
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Initialize Radar
        Radar.initialize(publishableKey: "YOUR_PUBLISHABLE_KEY")
        
        // Set up in-app message delegate
        Task { @MainActor in
            let delegate = MyInAppMessageDelegate()
            RadarInAppMessageManager.shared.setDelegate(delegate)
        }
        
        // Start tracking
        Radar.startTracking(trackingOptions: .presetResponsive)
        
        return true
    }
}

@available(iOS 13.0, *)
class MyInAppMessageDelegate: RadarInAppMessageDelegate {
    
    override func onNewInAppMessage(_ message: RadarInAppMessage) {
        // Show the message when received
        Task { @MainActor in
            await RadarInAppMessageManager.shared.showInAppMessage(message)
        }
    }
    
    override func onInAppMessageButtonClicked(_ message: RadarInAppMessage) {
        // Handle button click
        if let swiftMessage = message as? RadarInAppMessage_Swift,
           let button = swiftMessage.button,
           let deepLink = button.deepLink,
           let url = URL(string: deepLink) {
            
            // Open deep link
            UIApplication.shared.open(url)
        }
    }
}

Troubleshooting

  • Verify iOS version is 13.0 or later
  • Check that messages are configured correctly in the dashboard
  • Ensure the app has a key window available
  • Verify the delegate is set on the main thread
  • Check that no other message is currently being displayed
  • Ensure the delegate is set using RadarInAppMessageManager.shared.setDelegate()
  • Verify the delegate is set on the main thread with @MainActor
  • Check that the delegate is retained (not deallocated)