Using the SDK with your own IAP Code (formerly: Observer Mode)
If you already have your own in-app purchase handling logic in your app and want to start using RevenueCat alongside it, you might need to set the SDK configuration option that your app will complete the purchases itself (configuration option purchasesAreCompletedBy
, see code below). Completing a purchase tells the device billing library that a purchase has been processed and can be discarded. RevenueCat does this by default, however, this may interfere with pre-existing purchase handling code in your app.
If you set the SDK option that your app will complete purchases itself, you can still make use of most of RevenueCat's features, without replacing your existing purchase handling code. If you're making purchases on iOS, be sure to set the storeKitVersion
to the version of StoreKit you're using.
The setting where your app completes purchases was formerly called "observer mode". Older versions of the SDK (currently including the iOS and cross-platform SDKs) still refer to this terminology.
For Amazon Appstore apps, you will need to call the syncAmazonPurchase()
method after making a purchase using your own IAP code.
SDK Configuration
- Swift
- Obj-C
- Java
- Flutter
- React Native
- Unity
Purchases.configure(
with: .init(withAPIKey: "<public_sdk_key>")
.with(purchasesAreCompletedBy: .myApp, storeKitVersion: .storeKit2)
)
RCPurchases.logLevel = RCLogLevelDebug;
[RCPurchases configureWithAPIKey:@<public_sdk_key>
appUserID:@<app_user_id>
purchasesAreCompletedBy:RCPurchasesAreCompletedByRevenueCat
storeKitVersion:RCStoreKitVersion2];
// If you're targeting only Google Play Store
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Purchases.setLogLevel(LogLevel.DEBUG);
Purchases.configure(
new PurchasesConfiguration.Builder(this, <public_google_sdk_key>)
.purchasesAreCompletedBy(PurchasesAreCompletedBy.MY_APP)
.build()
);
}
}
// If you're building for the Amazon Appstore
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Purchases.setLogLevel(LogLevel.DEBUG);
PurchasesConfiguration.Builder builder = null;
if (BuildConfig.STORE.equals("amazon")) {
builder = new AmazonConfiguration.Builder(this, <public_amazon_sdk_key>);
} else if (BuildConfig.STORE.equals("google")) {
builder = new PurchasesConfiguration.Builder(this, <public_google_sdk_key>);
}
Purchases.configure(
builder
.purchasesAreCompletedBy(PurchasesAreCompletedBy.MY_APP)
.build()
);
}
}
PurchasesConfiguration configuration = PurchasesConfiguration(<public_sdk_key>);
configuration.purchasesAreCompletedBy = PurchasesAreCompletedByMyApp(
storeKitVersion: StoreKitVersion.storeKit2,
);
await Purchases.configure(configuration);
Purchases.configure({
apiKey: "your_api_key_here",
purchasesAreCompletedBy: {
type: PURCHASES_ARE_COMPLETED_BY_TYPE.MY_APP,
storeKitVersion: STOREKIT_VERSION.STOREKIT_2,
},
});
// Observer mode can be configured through the Unity Editor.
// If you'd like to do it programmatically instead,
// make sure to check "Use runtime setup" in the Unity Editor, and then:
Purchases.PurchasesConfiguration.Builder builder = Purchases.PurchasesConfiguration.Builder.Init(< api_key >);
Purchases.PurchasesConfiguration purchasesConfiguration =
builder.SetUserDefaultsSuiteName("user_default")
.SetPurchasesAreCompletedBy(Purchases.PurchasesAreCompletedBy.MyApp, Purchases.StoreKitVersion.StoreKit2)
.SetAppUserId(appUserId)
.Build();
purchases.Configure(purchasesConfiguration);
Syncing Past Subscriptions
When using RevenueCat with your own IAP code, historical subscriptions won't automatically appear in the dashboard. To sync past subscriptions, you'll need to call syncPurchases()
after configuring the SDK. This method will:
- read the local App Store receipt (iOS) or query the billing library (Android) for existing transactions
- process historical transactions and associate them with the current appUserID
- activate entitlements and display the data in the dashboard
Call syncPurchases()
after a user logs in, rather than on every app launch. Calling it too frequently can cause unnecessary delays or disrupt the user experience, especially if your app has a large user base or complex entitlements.
syncPurchases()
only brings in data if the customer opens the app. Anyone inactive won't be included until they return. Additionally:
- On iOS, it only processes what's still in the local App Store receipt
- On Android, it only queries the BillingClient for currently owned subscriptions or non-consumed purchases
- It does not pull in all historical orders ever made on the store account — just what's currently accessible on that device/session
Alternative Approaches for Historical Data
If you need to backfill past subscriptions without depending on users launching the updated app, consider these alternative approaches:
-
Backend Import: Use our Migration to RevenueCat guide to implement a server-side migration. This approach:
- Allows you to send Apple receipts or Google purchase tokens directly to RevenueCat using the
POST /receipts
API reference. - Gives you complete control and can be scripted to run once or continuously
- Is ideal for fully backfilling past subscriptions
Note: The API has rate limits, so for large-scale migrations, consider implementing bulk processing with appropriate delays between batches.
For more details on importing historical purchases, see our Importing your Historical Purchases guide.
- Allows you to send Apple receipts or Google purchase tokens directly to RevenueCat using the
-
Google Historical Import: For Google Play apps, we offer a specialized Google Historical Import process that:
- Overcomes the 90-day token expiry limitation
- Captures a deeper purchase history
- Requires additional setup with Google Play Console
For Amazon Appstore apps, you'll need to manually sync each purchase using syncAmazonPurchase()
after making a purchase. See our Amazon Platform Resources for more details.
Restore Behavior Considerations
When syncing purchases, RevenueCat will handle existing subscriptions based on your restore behavior setting. This setting determines what happens when a user's purchases are already associated with a different App User ID.
For more information about restoring purchases and best practices, see our Restoring Purchases guide.