Skip to main content
πŸ“Œ Release Notes for August, Week 4: Promotion UI Templates are now available! Building a paywall has never been easier! Learn more
Version: Legacy

iOS SDK

The Monetai iOS SDK allows you to integrate our purchase prediction engine directly into your iOS app. This guide will walk you through the entire process, from installation to using key features like event tracking and purchaser prediction.

Prerequisites​

  • iOS 13.0 or higher
  • Xcode 12.0 or higher

πŸ“š Additional Resources​

  • GitHub Repository: https://github.com/hayanmind/monetai-ios
  • Example Apps: Check out various integration examples in the Examples folder of the GitHub repository
    • Swift Examples: SimpleApp, SwiftPackageManagerExample, CocoaPodsExample
    • Objective-C Examples: SimpleAppObjectiveC

πŸ”§ Language Support​

The Monetai iOS SDK supports both Swift and Objective-C. Select the appropriate tab below based on your project's language.


Essential SDK Setup​

πŸ“Œ This section covers the essential steps to install the Monetai SDK and configure it to collect the data needed for purchase predictions.
Please make sure to follow all three steps to lay the foundation for all promotion features.

1. SDK Installation​

Add the Monetai iOS SDK to your project using Swift Package Manager or CocoaPods.

  1. In Xcode, go to File > Add Package Dependencies
  2. Enter the repository URL: https://github.com/hayanmind/monetai-ios
  3. Select the latest version and click Add Package
  4. Choose your target and click Add Package

2. SDK Initialization​

Initialize the SDK when your app launches.

import MonetaiSDK

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

// Initialize Monetai SDK
Task {
do {
let result = try await MonetaiSDK.shared.initialize(
sdkKey: "YOUR_SDK_KEY", // SDK key issued from Monetai dashboard
userId: "USER_ID", // User ID of your app's user
useStoreKit2: true // Set based on the purchase logic implemented in your app
)

print("Monetai SDK initialization completed:", result)
} catch {
print("Monetai SDK initialization failed:", error)
}
}

return true
}

API Reference

Parameters

ParameterTypeDescription
sdkKeystringSDK key issued from Monetai (Settings > SDK Integration)
userIdstringUser ID of your app's user (if not available, use a unique identifier such as email or device ID)
useStoreKit2boolean?Whether to use StoreKit2 (set based on the purchase logic implemented in your app, default: false)

Return Value

Return ValueTypeDescription
organizationIdnumberOrganization ID
platform'ios'Platform info
versionstringSDK version
userIdstringSet user ID
groupABTestGroup | nullA/B test group

ABTestGroup Type

ValueDescription
monetaiExperimental group with automatic promotion
baselineControl group without promotion
unknownUsers not included in campaign
nullWhen no current campaign exists

3. Logging User Events​

This is a critical step. Monetai's AI model relies entirely on the user events you log to analyze behavior and predict purchase intent. Without this data, the prediction feature will not function.


import MonetaiSDK

// Basic event logging
await MonetaiSDK.shared.logEvent(eventName: "app_in")

// Event logging with parameters
await MonetaiSDK.shared.logEvent(
eventName: "screen_in",
params: ["screen": "home"]
)

API Reference

Parameters

ParameterTypeDescription
eventNamestringEvent name
paramsobject?Event parameters (optional)
Event Logging Tips
  • Log all in-app events. Monetai will automatically select events most relevant to non-payer prediction for training.
  • If no events are logged, instrument events on key features or buttons, especially those that occur before a purchase.
Event Handling Before Initialization

Events logged before the SDK is initialized are queued and sent automatically once initialization is complete.

Parameter Usage Guidelines

Important: Even with the same event name, different parameters create different events that the AI model recognizes separately. Using too many diverse parameter values can reduce model accuracy.

Best Practices:

  • βœ… Good: ["screen": "home"], ["button": "upgrade"], ["category": "premium"]
  • ❌ Avoid: ["timestamp": "2024-01-15T10:30:00Z"], ["userId": "user123"], ["sessionId": "abc123"]

Why? Parameters like timestamps, user IDs, or session IDs create unique events for each occurrence, making it difficult for the model to find patterns. Focus on parameters that represent user behavior categories rather than specific instances.


Implementing Promotions​

πŸ“Œ With the essential setup complete, this section dives into implementing the core promotion logic.
You'll learn how to trigger purchase predictions and use the results to display your custom promotional UI.

1. Predicting Purchases​

CCall the predict() function at a key purchase decision moment within your app to predict whether a user is likely to make a purchase.

[Recommended] Call predict at Only One Point!
  • To optimize the user experience and most clearly measure campaign performance, we strongly recommend calling the predict() function at only one specific point in the user journey.
  • It's most effective to call it at the critical moment of hesitationβ€”after the user has recognized the product's value but is still deciding whether to purchase.
    Depending on your app's characteristics, consider points like:
    • When the user navigates away from the full-price subscription page.
    • When the user completes a core workflow or task.
    • When the user attempts to access or use a premium feature.
import MonetaiSDK

func predictUserPurchase() async {
do {
let result = try await MonetaiSDK.shared.predict()

print("Prediction result:", result.prediction)
print("Test group:", result.testGroup)

if result.prediction == .nonPurchaser {
// When predicted as non-purchaser, offer discount
print("Predicted as non-purchaser - discount can be applied")
} else if result.prediction == .purchaser {
// When predicted as purchaser
print("Predicted as purchaser - discount not needed")
}
} catch {
print("Prediction failed:", error)
}
}

API Reference

Return Value

Return ValueTypeDescription
predictionPredictResultPrediction result
testGroupABTestGroupA/B test group

PredictResult Type

ValueDescription
nonPurchaserPredicted not to purchase
purchaserPredicted to purchase
nullCannot predict (before model creation or no active campaign)
Important Notes for predict() Function
  1. Multiple Calls
    • When a promotion is already active from a previous predict() call, calling predict() multiple times will not start a new promotion.
  2. Restarting Promotions
    • After a promotion period ends, calling predict() again will start a new promotion if the user is still predicted as a non-paying user.
  3. Handling Existing Subscribers
    • If you do not want to provide promotions to users who are already on paid subscriptions, do not call the predict() function for those users.

2. Displaying Promotion UI​

When predict() identifies a user as a non-paying user, the SDK delivers discount information via the onDiscountInfoChange callback. You can use this to display promotional UI to the user.

Pass paywallConfig to MonetaiSDK.shared.configurePaywall(). When predict() returns a non-purchaser and the discount is within its valid period, the banner/paywall will appear automatically.

Paywall UI Template Support

Paywall UI templates are supported in iOS SDK 1.2.0 and above.

Explore UI templates

See available template styles and examples: UI Template Design Guide

import MonetaiSDK

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// Configure paywall
configurePaywall()

// Set subscription status (set initial value based on the user's actual subscription status)
MonetaiSDK.shared.setSubscriptionStatus(false)
}

private func configurePaywall() {
let features = [
Feature(title: "All premium features", description: "Unlock everything", isPremiumOnly: true),
Feature(title: "Advanced analytics", description: "Insights and detailed reports"),
Feature(title: "Priority support", description: "24/7 customer support")
]

let config = PaywallConfig(
discountPercent: 50,
regularPrice: "$10.00",
discountedPrice: "$5.00",
locale: "en",
style: .highlightBenefits,
features: features,
enabled: true,
bannerBottom: 20
)

config.onPurchase = { [weak self] close in
// TODO: Trigger your purchase flow
// On success, close paywall and update subscriber state
close()
MonetaiSDK.shared.setSubscriptionStatus(true)
}

config.onTermsOfService = {
// TODO: Open Terms of Service
}

config.onPrivacyPolicy = {
// TODO: Open Privacy Policy
}

MonetaiSDK.shared.configurePaywall(config)
}
}

PaywallConfig

KeyTypeRequiredDescription
discountPercentIntβœ“Discount percentage (0-100)
regularPriceStringβœ“Regular price label
discountedPriceStringβœ“Discounted price label
localeStringβœ“Language code (e.g., "en", "ko")
stylePaywallStyleβœ“Template style
features[Feature]-Only needed for .highlightBenefits or .keyFeatureSummary
enabledBool-Enable automatic banner/paywall display (default: true)
bannerBottomCGFloat-Bottom offset for the floating banner (default: 20)

PaywallStyle Types

ValueDescription
.compactCompact design
.highlightBenefitsHighlight benefits design
.keyFeatureSummaryKey feature summary design
.textFocusedText-focused design

Feature Model

PropertyTypeDescription
titleStringFeature title
descriptionStringFeature description
isPremiumOnlyBoolWhether feature is premium only (default: false)

Callbacks

CallbackTypeDescription
onPurchase((@escaping () -> Void) -> Void)?Purchase button callback (call close() on success)
onTermsOfService(() -> Void)?Terms of Service click callback
onPrivacyPolicy(() -> Void)?Privacy Policy click callback

Subscription Status Management

The SDK automatically controls banner/paywall visibility based on the user's subscription status. Use these methods to manage the subscription state:

// Set initial subscription status (can be called before or after configurePaywall)
MonetaiSDK.shared.setSubscriptionStatus(true) // true for subscribers, false for non-subscribers

Automatic Banner Control

When paywall is configured, the SDK automatically:

  • Shows the banner when discount is active, paywall is enabled, and user is not a subscriber
  • Hides the banner when user is a subscriber, no discount exists, discount has expired, or paywall is disabled

B. Custom UI (Advanced)​

B-1. Implementation using onDiscountInfoChange callback

Implementing Custom UI

You can build your own promotion screen. The Monetai SDK provides the discount timing (startedAt and endedAt) and triggers the onDiscountInfoChange callback. Your app can use this information to implement the custom UI components.

The startedAt and endedAt values in the discount information indicate the valid period for the promotion. You should use these timestamps to:

  • Show your promotion screen only during the valid period
  • Hide the screen when the period expires
Callback Registration Timing

Important: The onDiscountInfoChange callback must be registered before calling initialize().

Registering the callback later may cause you to miss existing active promotion information. This can lead to issues where previously activated promotions cannot be displayed immediately when the app restarts.

Real-Time UI Updates

The onDiscountInfoChange callback is triggered both when the app starts and there's valid discount information and when a new discount is generated by a predict() call. Use it to update banners, prices, or other UI elements in real-time.

import MonetaiSDK

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// Set up discount info change callback
MonetaiSDK.shared.onDiscountInfoChange = { [weak self] discountInfo in
DispatchQueue.main.async {
self?.handleDiscountInfoChange(discountInfo)
}
}
}

private func handleDiscountInfoChange(_ discountInfo: AppUserDiscount?) {
if let discount = discountInfo {
// Update UI when discount info is available
let now = Date()
let endTime = discount.endedAt

if now < endTime {
// When discount is valid
showDiscountBanner(discount)
}
} else {
// When no discount info
hideDiscountBanner()
}
}

private func showDiscountBanner(_ discount: AppUserDiscount) {
// Show discount banner logic
print("Show discount banner:", discount)
}

private func hideDiscountBanner() {
// Hide discount banner logic
print("Hide discount banner")
}
}

API Reference

Callback Type

public var onDiscountInfoChange: ((AppUserDiscount?) -> Void)?

AppUserDiscount Type

PropertyTypeDescription
startedAtDateDiscount start time
endedAtDateDiscount end time
appUserIdstringUser ID
sdkKeystringSDK key

B-2. Reactive implementation using currentDiscount property

You can use the currentDiscount property to immediately access currently active discount information. You can check the current discount status without the onDiscountInfoChange callback.

The onDiscountInfoChange callback has a constraint that it must be registered before calling initialize() to avoid missing events. However, if you want to bypass this constraint and implement in a more flexible way, you can consider using reactive processing with @Published objects and Combine.

API Reference

Current discount information property

@Published public private(set) var currentDiscount: AppUserDiscount?

Managing User State​

SDK Reset​

Initialize the SDK when the user logs out.

import MonetaiSDK

// When user logs out
func logoutUser() {
MonetaiSDK.shared.reset()
print("User logout completed")
}

Support
If you run into any trouble during the integration, don't hesitate to contact us at support@monetai.io.


Next Steps​

With the SDK setup complete, you're ready to create a model and launch a campaign: