Add in-app campaigns to iOS
Show targeted announcements as native cards and banners when your app is ready.
Enable in-app campaigns
In-app campaigns require BTXClientKit 3.3.1 or later and campaign access for your project. Check the changelog for release availability.
Add .inAppCampaigns to your existing configuration and identify the signed-in customer with a stable external ID. Include .helpCenter if campaign actions open Help Center articles; HTTPS actions do not require it. Keep any other capabilities your app already uses.
import BTXClientKit
BTX.configure(
BTXConfiguration(
publishableClientKey: "cfk_...",
features: [.inAppCampaigns, .helpCenter]
)
)
BTX.identify(BTXCustomer(externalID: currentUser.id))Signal when the app is ready
After verifying the host app session and displaying its signed-in screen, signal readiness on the main actor:
// After verifying sign-in and displaying the host screen:
BTX.inAppCampaigns.setPresentationReady(true)Readiness defaults to false on each launch. The SDK waits two seconds after readiness, then waits for a safe active window without a modal, keyboard, or another SDK presentation. Repeated true calls do not restart the delay. Visible campaigns yield when your app opens a modal, starts text entry, begins a navigation transition, or becomes inactive. The SDK does not dismiss your app’s UI.
Set readiness to false before a flow where campaign presentation would be inappropriate. This cancels pending presentation and dismisses visible content. Restore it only after the host is ready again. Before sign-out or account switching, also clear the identity:
// Before sign-out or account switching:
BTX.inAppCampaigns.setPresentationReady(false)
BTX.identify(nil)Changing the customer or publishable client key resets readiness. Updating the same customer's profile does not. A credential refresh keeps the current selection. Returning from the background starts a new selection cycle without resetting host readiness.
Understand campaign delivery
The SDK selects the customer's oldest active queued campaign when the app launches and each time it returns from the background. It attempts at most one automatic card or banner per cycle and requires an internet connection. On return, it waits two seconds and checks host readiness and the active screen. Temporary interruptions, such as closing Control Center, do not start another cycle. Campaigns started while the app is open become eligible on its next return from the background or launch.
Paused campaigns are skipped and keep their queue position when resumed. Content edits apply to pending deliveries. Content already reserved by the app for display stays unchanged. If an edit invalidates the app's pending content, presentation waits until a later launch or return from the background.
Views, clicks, and dismissals are saved across restarts and sent when connectivity is available. An uncertain presentation is not repeated. A confirmed presentation failure can retry on a later launch or return from the background. See the campaign guide for audience selection and delivery results.
Version 3.4.2 adds specific diagnostics for image-loading and presentation failures. With .logs enabled, the SDK also reports in_app_campaign.presentation_failed so you can connect an error to its delivery attempt. Diagnostics exclude image URLs, response bodies, and customer content. Temporary screen interruptions defer delivery without displaying an error in campaign results. No additional configuration is required for delivery diagnostics.
Match your app's theme
Campaigns inherit messengerOptions.theme unless you provide BTXInAppCampaignOptions(theme:). Use the same BTXTheme as your other SDK surfaces:
BTX.configure(
BTXConfiguration(
publishableClientKey: "cfk_...",
features: [.inAppCampaigns, .helpCenter],
inAppCampaignOptions: BTXInAppCampaignOptions(theme: appTheme)
)
)Cards use titleFont and bodyFont. Banners use the same typography and text colors as support-message notifications, with bodyFont for both title and message. Banners without an action link retain normal text contrast. On iOS 26 and later, foregroundNotificationGlassStyle selects clear or regular glass for both presentations. Clear glass includes the same blur layer used by other SDK surfaces to keep the host screen from competing with campaign content. Campaigns also use the foreground notification background, material opacity, and stroke settings. Card background dimming is separate from the glass style. Card actions use titleFont, primaryCTAColor, primaryCTATextColor, primaryCTAStrokeColor, and primaryCTAStyle. Register custom fonts in the host app before using them.
Banner bodies use at most two lines. The entire banner content opens its action; the close button only dismisses it. Cards and banners prepare artwork before appearing, so images and text display together. Banners use the project logo when no custom artwork is set. If artwork cannot be loaded, the campaign stays hidden and can retry on a later launch or return from the background. Artwork downloads are limited to 10 MiB.
Artwork supports GIFs, pauses animation while inactive, and uses a still frame with Reduce Motion. Longer animations are sampled to at most 120 frames while preserving total playback duration. Frames are resized to keep decoded artwork within 64 MiB.
Cards without an attached image show text and actions only. The SDK does not insert a logo or image placeholder. Banners can still use the project icon when no custom artwork is attached.
Verify the integration
Run the app with a test customer and exercise the full path before shipping.
- Create a card and a banner for a segment containing only your test accounts.
- Confirm images and text appear together after sign-in and the readiness signal, including on a slow connection.
- Open the action destination, dismiss a campaign, and check the delivery results.
- Return from the background and restart the app to confirm eligible campaigns appear without repeating viewed content.
- Check sign-out, account switching, offline launch, and a screen that temporarily delays readiness.
If you enable campaign push, integrate push notifications and test on a physical device. Tapping a campaign notification opens that campaign once the app is ready, including when returning from the background. The SDK checks that the campaign is active and unseen for the signed-in customer and loads its current content. The tap does not open Messenger or execute the campaign action.