Skip to content
Last updated

iOS SDK Integration for Mobile In-App Messaging

The preview Engage Mobile SDK connects an iOS app to Engage Studio Mobile In-App Messaging. The app sends a trigger event with trackImmediately; the SDK requests an offer from Realtime Personalization, renders a supported message, and handles the WebView boundary.

Preview

The native SDK integration is in preview. APIs, package distribution, message payloads, and rendering behavior may change before general availability. Follow the release-specific SDK distribution instructions provided by Treasure AI.

What the SDK Does

The SDK is a thin client. Realtime Personalization decides whether to return an experience; the SDK executes the returned decision.

ResponsibilityOwner
Audience eligibility and delivery decisionsRealtime Personalization
Trigger event and app lifecycle timingCustomer app
Message selection from the responseSDK
Modal and Banner WebView renderingSDK
Hosted Pages URL renderingSDK
App-specific deep-link routingCustomer app
App-specific custom actionsCustomer app
Campaign impression, click, and dismiss measurementSDK

Before You Start

Prepare the following values:

  • A write-only API key for your Treasure AI account.
  • A records endpoint for the account region.
  • A Personalization endpoint.
  • A Personalization token.
  • A database and table for the trigger events.
  • An event schema that identifies the app screen or action that should trigger a message.

The SDK package declares iOS 12 or later support. Confirm the supported OS range for the preview artifact you receive before building your application.

Install the SDK Modules

The preview package provides two modules:

  • TreasureData — event collection, buffering, and upload.
  • TreasureDataEngage — the optional iOS WebKit rendering layer for Mobile In-App Messaging and Hosted Pages.

The distribution method for the preview package is not yet part of the public installation instructions. Contact your Treasure AI representative for preview access and the package version to use.

Quick Start

Import both modules and configure the SDK once during app startup.

import TreasureData
import TreasureDataEngage

TreasureData.initializeWithApiKey(
    "<WRITE_ONLY_API_KEY>",
    apiEndpoint: "https://<region>.records.in.treasuredata.com"
)

let td = TreasureData.sharedInstance()
td.defaultDatabase = "<DATABASE>"
td.defaultTable = "<EVENT_TABLE>"
td.personalizationEndpoint =
    "https://p13n-api.treasuredata.com"
td.personalizationToken = "<PERSONALIZATION_TOKEN>"

// Needed to associate measurement with an installation.
td.enableAutoAppendUniqId()

// Optional values exposed to the message as window.TDContext.
td.profileContext = [
    "member_tier": "gold"
]

// Required for rendering on iOS.
TDEngage.install()

Call trackImmediately when a screen or event that can trigger a message occurs:

td.trackImmediately([
    "event": "pageview",
    "screen_name": "home"
])

You can use the optional callback to determine whether the SDK displayed a message:

td.trackImmediately([
    "event": "pageview",
    "screen_name": "campaign"
], table: "<EVENT_TABLE>") { shown in
    print("In-App message shown: \(shown)")
}

addEvent and uploadEvents continue to send ordinary events. They do not trigger a Mobile In-App Message.

Configure the Core APIs

API or propertyPurpose
personalizationEndpointEndpoint used to request a message offer.
personalizationTokenRead credential used for Personalization. Keep it separate from the write API key.
defaultDatabase / defaultTableDefault destination used to build trigger requests and ordinary events.
trackImmediately(_:table:onResult:)Sends a trigger event and requests a message.
profileContextJSON-serializable values exposed to message content as window.TDContext.
TDEngage.install()Registers the iOS rendering layer with the core SDK.
linkHandlerLets the app claim custom schemes or other URLs.
bridgeDelegateReceives app-specific invoke calls from message content.
openUrl(_:context:)Displays a URL that the app already has, such as a URL from a push payload.

Message Flow

  1. The app calls trackImmediately(event).
  2. The TreasureData iOS SDK sends the trigger event to Personalization.
  3. Realtime Personalization returns an offer or no offer.
  4. TreasureDataEngage selects one displayable message.
  5. The SDK checks the one-message-at-a-time guard.
  6. The SDK renders Modal, Banner, or Hosted Pages.
  7. The app and message content handle the resulting interaction.

If no campaign matches, the SDK does not display anything. This is a normal result, not an error.

The SDK selects a single displayable message from the response. If another message is already visible, the new message is not displayed.

Hosted Pages

Hosted Pages is the customer-facing name for a campaign message whose content is loaded from a URL. The SDK displays the URL in a full-screen WebView and injects the configured profile context.

Use Hosted Pages for:

  • Coupon pages.
  • Stamp cards.
  • Lotteries and interactive promotions.
  • Surveys and forms.
  • Personalized campaign pages.

Hosted Pages does not use the Modal or Banner appearance settings. The hosted page is responsible for providing an appropriate way to leave the experience.

Campaign-Delivered Hosted Pages

When the app calls trackImmediately and Realtime Personalization returns a Hosted Pages offer, the SDK has the campaign identity needed for campaign measurement.

Direct URL Display

When the app already has a URL, it can call openUrl:

let url = URL(string: "https://example.com/coupon")!
TreasureData.sharedInstance().openUrl(
    url,
    context: ["coupon_id": "abc123"]
)

This is useful for the push-tap path. The URL is displayed in the SDK WebView, but it did not come from a campaign offer, so it does not produce campaign impression, click, or dismiss records.

Use linkHandler when the app owns a custom URL scheme:

td.linkHandler = { url in
    guard url.scheme == "engage-demo" else {
        return false
    }

    AppRouter.shared.open(url)
    return true
}

Return true only when the app handled the URL. If the handler returns false or is not configured, the SDK uses its default behavior for supported web URLs. Do not open a second browser from the app and then return false.

The handler is called synchronously on the main thread. Keep the handler short and route longer work to the appropriate app service after claiming the URL.

Handle Custom Actions

Message content can request app-specific behavior through the SDK bridge. The app receives the request through TDEngageBridgeDelegate:

final class EngageClient: NSObject, TDEngageBridgeDelegate {
    func handleTDBridgeInvoke(
        name: String,
        params: [String: Any]
    ) {
        switch name {
        case "grantPoints":
            // Check authentication, authorization, and parameter limits.
            break
        default:
            break
        }
    }
}

td.bridgeDelegate = engageClient

The SDK does not interpret the action name or authorize the request. Treat the message content and every parameter as untrusted input. The delegate is weak, so assign an object whose lifetime covers the app rather than a short-lived view controller.

Share Profile Context with Message Content

profileContext is injected into Modal, Banner, and Hosted Pages content as window.TDContext.

td.profileContext = [
    "member_tier": "gold",
    "points": 1200
]

Follow these rules:

  • Use JSON-serializable values only.
  • Set the context again after each app launch; it is not persisted by the SDK.
  • Clear or replace it when the signed-in customer changes.
  • Do not include API keys, tokens, passwords, or values that the Hosted Pages page should not see.
  • Pass large numeric identifiers as strings to avoid JavaScript precision loss.

Handle Screen Changes

The Personalization request is asynchronous. A customer can leave the triggering screen before the response arrives. The preview SDK exposes a presentation gate and returns the in-flight task from the callback overload so the host app can suppress or cancel a stale request.

Use this when a message must only appear on the screen that triggered it:

let task = td.trackImmediately([
    "event": "pageview",
    "screen_name": "checkout"
], table: "<EVENT_TABLE>") { shown in
    // Update app-level diagnostics if needed.
}

// Cancel when the triggering screen is no longer valid.
task?.cancel()

The exact presentation-gate API is part of the preview contract and may change before general availability.

Measurement

In the preview SDK flow, measurement is recorded automatically for campaign-delivered messages:

  • impression — the experience is presented.
  • click — a supported link or bridge action is used.
  • dismiss — the experience is closed.

enableAutoAppendUniqId() is effectively required when you need to associate these records with an installation. The measurement destination and schema may change before general availability.

For troubleshooting, see Mobile In-App Troubleshooting.

Minimal Integration Checklist

You can integrate the preview SDK without using a sample application repository.

  • Add the preview TreasureData and TreasureDataEngage modules through the distribution method provided with your SDK artifact.
  • Initialize the core SDK once during app startup.
  • Set the Personalization endpoint, token, database, and event table.
  • Call TDEngage.install() after core initialization.
  • Configure profileContext, linkHandler, and bridgeDelegate only when your content needs them.
  • Call trackImmediately when the configured screen or event occurs.
  • Test Modal, Banner, and Hosted Pages on supported iOS devices.
  • Register Push tokens separately if the app uses Mobile Push.
  • Verify impression, click, dismiss, Deep Link, and Hosted Pages behavior before release.

The preview SDK's package name, version, and distribution URL are release-specific. Use the installation instructions that accompany the artifact rather than a source repository URL.