SDK Migration Guide
This guide helps existing Monetai customers migrate from the prediction-based SDK (non-purchaser prediction & campaign-driven revenue optimization) to the current SDK (personalized pricing-based revenue optimization). It covers all the changes you need to make — from dashboard concepts to SDK code updates.
What's Changed
How Monetai Works — Before and After
Before (Prediction-Based): The SDK predicted whether each user was a purchaser or non-purchaser, then showed a fixed discount to predicted non-purchasers. Campaigns were the unit that ran promotions. A trained AI model (requiring 200+ users) was necessary before campaigns could run.
Now (Personalized Pricing-Based): The SDK retrieves a personalized offer for each promotion, with AI-optimized discount rates per product. Promotions are a new top-level concept that represent a purchase page in your app. Within each promotion, Agents (the evolution of Campaigns) handle per-platform pricing optimization with targeting rules. AI optimization starts immediately — no minimum data threshold required.
Concept Mapping
| Before | Now | What Changed |
|---|---|---|
| Campaign | Agent | Campaigns evolved into Agents — the core optimization unit, now with targeting rules and priority |
| (no equivalent) | Promotion | New concept: groups agents together, represents a single purchase page in your app |
| predict() — classifies users as purchaser / non-purchaser | getOffer(placement) — retrieves a personalized offer for a specific placement | New API that returns per-product discount rates for a given placement |
| onDiscountInfoChange callback | getOffer() return value | Discount info is now returned directly instead of via callback |
| Model Generation (requires 200+ users) | AI Pricing Optimization (starts immediately) | No waiting for model training |
| Fixed discount (show/hide) | Dynamic discount rate per product | AI optimizes the discount rate automatically |
Step-by-Step Migration
Step 1: Update SDK Version
Update to the latest SDK version.
- React Native
- iOS
- Android
yarn add @hayanmind/monetai-react-native@latest
For iOS, run cd ios && pod install after updating.
Update via Swift Package Manager (select latest version) or CocoaPods:
pod 'MonetaiSDK' # Update to latest
pod install
Update the dependency in your build.gradle:
dependencies {
implementation 'com.github.hayanmind:monetai-android:2.0.0'
}
SDK v2.0.0 uses Google Play Billing Library v8. If you use other billing libraries, ensure they support Billing Library v8.
Step 2: Update SDK Initialization
The initialize() call remains the same. However, the return value no longer includes the group field.
- React Native
- iOS (Swift)
- Android (Kotlin)
// Before: return value included `group`
// Now: `group` is removed — no longer returned
const result = await MonetaiSDK.initialize({
sdkKey: "YOUR_SDK_KEY",
userId: "USER_ID",
useStoreKit2: true,
});
// result no longer contains .group
// Before: return value included `group`
// Now: `group` is removed — no longer returned
let result = try await MonetaiSDK.shared.initialize(
sdkKey: "YOUR_SDK_KEY",
userId: "USER_ID",
useStoreKit2: true
)
// result no longer contains .group
// Before: return value included `group`
// Now: `group` is removed — no longer returned
MonetaiSDK.shared.initialize(
context = this,
sdkKey = "YOUR_SDK_KEY",
userId = "USER_ID"
) { result, error ->
// result no longer contains .group
}
If you used group / testGroup to branch logic in your app, you can safely remove that code. getOffer() handles this internally — a null return means no offer is available for that user.
Step 3: Remove predict() and Add getOffer()
This is the most significant change. The old predict() method — which classified users as purchasers or non-purchasers — is removed. In its place, you'll use getOffer(placement:), a new API that retrieves a personalized offer for a specific placement.
What is
placement? Aplacementis a unique string identifier for the screen where pricing optimization is applied. Define a descriptive value (e.g.,main_paywall,special_offer). If you've already created a promotion in the dashboard, you can find its placement value in Dashboard → Promotions → Promotion Settings.
These two APIs serve different purposes:
predict() (removed) | getOffer() (new) | |
|---|---|---|
| Purpose | Classify users (purchaser vs. non-purchaser), then show a fixed discount to non-purchasers | Get a personalized offer with AI-optimized discount rates per product |
| Input | None | placement (string identifier for the screen/UI component) |
| Return | prediction + testGroup | Offer object with per-product discountRate, or null |
| When to call | When deciding whether to show a promotion to the user | When displaying a pricing screen at a specific placement |
| Discount info | Delivered later via onDiscountInfoChange callback | Returned directly in the response |
- React Native
- iOS (Swift)
- Android (Kotlin)
// ❌ Remove: predict()
const result = await MonetaiSDK.predict();
if (result.prediction === "non-purchaser") {
showDiscountUI();
}
// ✅ Add: getOffer() — retrieve a personalized offer for a placement
const offer = await MonetaiSDK.getOffer("YOUR_PLACEMENT");
if (offer) {
// Offer available — apply the AI-optimized discount to your pricing screen
console.log("Discount rate:", offer.discountRate);
displayPrice(offer);
} else {
// No offer — show your app's default pricing
displayDefaultPrice();
}
// ❌ Remove: predict()
let result = try await MonetaiSDK.shared.predict()
if result.prediction == .nonPurchaser {
showDiscountUI()
}
// ✅ Add: getOffer() — retrieve a personalized offer for a placement
let offer = try await MonetaiSDK.shared.getOffer(placement: "special_offer")
if let offer = offer {
// Offer available — apply the AI-optimized discount to your pricing screen
for product in offer.products {
print("SKU: \(product.sku), Discount: \(product.discountRate * 100)%")
}
showPricingScreen(with: offer)
} else {
// No offer — show your app's default pricing
showDefaultPrice()
}
// ❌ Remove: predict()
MonetaiSDK.shared.predict { result, error ->
if (result?.prediction == PredictResult.NON_PURCHASER) {
showDiscountUI()
}
}
// ✅ Add: getOffer() — retrieve a personalized offer for a placement
MonetaiSDK.shared.getOffer(placement = "special_offer") { offer, error ->
if (offer != null) {
// Offer available — apply the AI-optimized discount to your pricing screen
offer.products.forEach { product ->
println("SKU: ${product.sku}, Discount: ${product.discountRate * 100}%")
}
displayPrice(offer)
} else {
// No offer — show your app's default pricing
displayDefaultPrice()
}
}
Step 4: Add logViewProductItem() (New — Required)
A new required logging call. Whenever a user views a pricing screen, you must call logViewProductItem() for each product displayed. This data is essential for AI pricing optimization.
Pricing screens — pass placement to identify the screen:
- React Native
- iOS (Swift)
- Android (Kotlin)
// Call for each product shown on the pricing screen
await MonetaiSDK.logViewProductItem({
placement: "special_offer",
productId: "premium_monthly",
price: 4.99, // Displayed (discounted) price
regularPrice: 9.99, // Original price
currencyCode: "USD",
});
// Call for each product shown on the pricing screen
await MonetaiSDK.shared.logViewProductItem(
ViewProductItemParams(
placement: "special_offer",
productId: "premium_monthly",
price: 4.99, // Displayed (discounted) price
regularPrice: 9.99, // Original price
currencyCode: "USD"
)
)
// Call for each product shown on the pricing screen
MonetaiSDK.shared.logViewProductItem(
ViewProductItemParams(
placement = "special_offer",
productId = "premium_monthly",
price = 4.99, // Displayed (discounted) price
regularPrice = 9.99, // Original price
currencyCode = "USD"
)
)
Non-Monetai purchase screens — recommended for better price prediction accuracy:
- React Native
- iOS (Swift)
- Android (Kotlin)
await MonetaiSDK.logViewProductItem({
placement: "main_paywall",
productId: "premium_monthly",
price: 9.99,
regularPrice: 9.99,
currencyCode: "USD",
});
await MonetaiSDK.shared.logViewProductItem(
ViewProductItemParams(
placement: "main_paywall",
productId: "premium_monthly",
price: 9.99,
regularPrice: 9.99,
currencyCode: "USD"
)
)
MonetaiSDK.shared.logViewProductItem(
ViewProductItemParams(
placement = "main_paywall",
productId = "premium_monthly",
price = 9.99,
regularPrice = 9.99,
currencyCode = "USD"
)
)
If you skip this step, AI pricing optimization will not function correctly. Make sure to add logViewProductItem() calls for every product view.
Step 5: Remove Deprecated Code
Remove the following code that is no longer needed:
5-1. Remove onDiscountInfoChange callback
Discount information is now returned directly from getOffer(). The onDiscountInfoChange callback is no longer used.
- React Native
- iOS (Swift)
- Android (Kotlin)
// ❌ Remove onDiscountInfoChange prop
<MonetaiProvider onDiscountInfoChange={handleDiscountInfoChange}>
{/* ... */}
</MonetaiProvider>
// ❌ Remove this
MonetaiSDK.shared.onDiscountInfoChange = { discountInfo in
// ...
}
// ❌ Remove this
MonetaiSDK.shared.onDiscountInfoChange = { discountInfo ->
// ...
}
5-2. Remove predict() calls
// ❌ Remove all predict() calls
let result = try await MonetaiSDK.shared.predict()
5-3. Remove group handling
// ❌ Remove group/testGroup branching logic
if result.testGroup == .monetai { ... }
if result.testGroup == .baseline { ... }
Step 6: Remove UI Templates (If Used)
Banner and Paywall UI templates are no longer provided. Price optimization via getOffer() is applied directly to your app's own promotion or pricing screen, so separate UI templates are no longer needed.
If you used configurePaywall() or the standalone Banner/Paywall components, remove them and integrate getOffer() into your existing purchase flow instead. See Step 3 for details.
- React Native
- iOS (Swift)
- Android (Kotlin)
// ❌ Remove these imports and usages
import { Banner, Paywall } from "@hayanmind/monetai-react-native";
// ❌ Remove these
MonetaiSDK.shared.configurePaywall(config)
MonetaiSDK.shared.setSubscriptionStatus(false)
// ❌ Remove these
MonetaiSDK.shared.configurePaywall(config)
MonetaiSDK.shared.setSubscriptionStatus(false)
Step 7: Set Up Promotions & Agents in Dashboard
In the previous version, you created Campaigns directly. Now there are two concepts: Promotions (new — representing a purchase page in your app) and Agents (evolved from Campaigns — the AI optimization unit within a promotion).
| Before | Now |
|---|---|
| Create a Campaign | Create a Promotion (products & discount pricing), then create Agents within it |
| Wait for model training (100+ payers / 100+ non-payers) | No waiting — AI optimization starts immediately |
| Start Campaign | Start an Agent per platform (iOS / Android) |
| Monitor Campaign metrics | Monitor per-Agent metrics within the Promotion |
For detailed instructions, see: Creating & Managing Promotions
Migration Checklist
Use this checklist to verify your migration is complete:
- SDK version updated to latest
-
predict()removed -
getOffer(placement:)added on pricing / promotion screens -
logViewProductItem()added for every product view on pricing screens -
onDiscountInfoChangecallback removed -
configurePaywall()and Banner/Paywall UI templates removed (if applicable) -
testGroup,ABTestGroupand other group handling code removed -
logEvent()calls remain in place (no changes needed) -
reset()call on logout remains in place (no changes needed) - Dashboard: Promotion created with products and agents configured
- Tested: Verified
getOffer(placement:)returns expected offer on test device
What Stays the Same
These parts of the SDK require no changes:
| Feature | Notes |
|---|---|
initialize() | Same API (group field removed from return value) |
logEvent() | Identical — keep logging user events as before |
reset() | Identical — call on user logout |
| SDK Installation | Same package managers (SPM, CocoaPods, Gradle, yarn/npm) |
FAQ
Q. Can I run the old campaigns and new promotions at the same time? A. No. You should complete the migration and switch entirely to the new promotion system.
Q. Do I need to wait for a model to be trained before starting? A. No. Unlike the previous version which required 200+ users before model training, the current version's global optimization starts working immediately after SDK integration.
Q. What happens to my existing campaign data? A. Your historical campaign data remains accessible in the dashboard. New metrics will be tracked under the promotion system.
Q. The old SDK returned prediction (purchaser/non-purchaser). How do I handle that logic now?
A. You don't need to classify users anymore. Instead, call getOffer() for a specific promotion — if an offer is returned, apply the discount; if null is returned, show your default pricing. The AI handles user targeting internally.
Q. What's the relationship between Promotions and Agents? A. A Promotion represents a purchase page in your app (e.g., an onboarding offer, a churn-prevention offer). Within each promotion, you create Agents — one or more per platform (iOS / Android) — which handle the actual AI pricing optimization. Campaigns evolved into Agents, and Promotions are a new layer above them.
Support
If you run into any issues during migration, contact us at support@monetai.io.