
Revenuecat Migrate
- 262 installs
- 55 repo stars
- Updated August 3, 2026
- revenuecat/ai-toolkit
Migrate existing subscribers from Stripe, native stores, or legacy billing into RevenueCat without double-charging, entitlement loss, or broken renewal states.
About
Assists agents migrating subscriptions to RevenueCat: map legacy products to offerings, import historical purchasers, validate entitlements, plan staged cutovers, and avoid renewal breaks when switching from native or third-party billing.
- Subscriber import playbooks
- Product and entitlement mapping
- Receipt and transaction transfer
- Cutover and rollback planning
- Store billing continuity checks
Revenuecat Migrate by the numbers
- 262 all-time installs (skills.sh)
- +28 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #1,458 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/revenuecat/ai-toolkit --skill revenuecat-migrateAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 262 |
|---|---|
| repo stars | ★ 55 |
| Last updated | August 3, 2026 |
| Repository | revenuecat/ai-toolkit ↗ |
What it does
Migrate existing subscribers from Stripe, native stores, or legacy billing into RevenueCat without double-charging, entitlement loss, or broken renewal states.
Files
revenuecat-migrate: migrate to RevenueCat or upgrade the SDK
Use this skill when the user wants to either adopt RevenueCat in an app that already ships in app purchases, or upgrade the RevenueCat SDK across a major version.
These two paths share some concepts but have different risks. Identify which one applies before touching code.
1. Detect the platform
Inspect the working directory and pick the first match, from top to bottom:
1. React Native: package.json has a react-native-purchases entry, or react-native as a dependency → read platforms/react-native.md. If expo is also a dependency, note it as an Expo project. 2. Flutter: pubspec.yaml exists at the project root → read platforms/flutter.md. 3. Kotlin Multiplatform: build.gradle.kts contains a kotlin { … } multiplatform source sets block, or depends on com.revenuecat.purchases:purchases-kmp* → read platforms/kmp.md. 4. Android (native): build.gradle(.kts) applies com.android.application (and is not KMP) → read platforms/android.md. 5. iOS (native): Package.swift, *.xcodeproj, *.xcworkspace, or Podfile at the project root → read platforms/ios.md.
If several match (e.g. an ios/ folder inside a Flutter project), pick the outermost project, the one that owns the build. If still ambiguous, ask the user which platform they want to configure.
2. Identify the migration path
Ask the user (or infer from the codebase):
- Path A: adoption. The app already has working in app purchases implemented directly against StoreKit or Google Play Billing. RevenueCat is being added on top.
- Path B: version upgrade. The app already uses RevenueCat, and the user wants to bump from one major version to the next (e.g. v4 to v5, v7 to v8).
Both paths can happen at once (e.g. adopt RC today on the latest major version). Run Path A first, then Path B if needed.
3. Shared concepts
Observer mode (Path A)
Observer mode is the key lever for adopting RevenueCat without rewriting purchase code. The SDK observes transactions that your existing StoreKit / Billing code processes, sends them to the RevenueCat backend for validation, and updates subscriber state, but does not initiate or finish the transactions. Your existing purchase UI, receipt validation, and transaction finishing stay in place.
Set this at configure time:
- iOS: set
purchasesAreCompletedBy: .myApptogether withstoreKitVersion: .storeKit1(or.storeKit2) onConfiguration.Builder. They are separate parameters, not a single associated value. - Android:
purchasesAreCompletedBy(PurchasesAreCompletedBy.MY_APP)onPurchasesConfiguration.Builder. - Flutter: pass
const PurchasesAreCompletedByMyApp(storeKitVersion: StoreKitVersion.storeKit2)toPurchasesConfiguration. - React Native: pass
purchasesAreCompletedBy: { type: PURCHASES_ARE_COMPLETED_BY_TYPE.MY_APP, storeKitVersion: STOREKIT_VERSION.STOREKIT_2 }in the configure call.
The default is RevenueCat completed (REVENUECAT / .revenueCat), where the SDK owns the full flow.
Once stable in observer mode, you can optionally cut over to full RevenueCat mode later by removing your own purchase plumbing and dropping the purchasesAreCompletedBy override.
Do not double process transactions
When purchasesAreCompletedBy is set to myApp, RevenueCat does not finish transactions on iOS or acknowledge on Android. Your existing code must continue to do that. If you remove the myApp flag while leaving your old transaction finishing code in place, transactions get acknowledged twice and subscriber state can appear inconsistent.
Exactly one side must own finishing / acknowledging. Pick a side and remove the other.
User continuity (Path A)
If the app already has its own authentication system, call Purchases.logIn(existingAppUserID) once RevenueCat is configured. This attaches the prior purchase history to the right RevenueCat user on ingestion. Without this step, existing purchases get recorded against an anonymous RC user and cannot be matched to the app's actual user records later.
Only skip this if the app has no notion of authenticated users.
Version bumps change required fields (Path B)
Major version upgrades change configuration shape, drop deprecated APIs, and shift default behavior in ways that move with each release. This skill does not duplicate the per-version diff. Read the canonical sources from the SDK repo:
- CHANGELOG: in the relevant SDK repo on GitHub. Walk entries from your installed version up to the target.
- Migration guides: search the SDK repo for files matching
*MIGRATION*.mdor amigrations/directory. Major bumps usually ship a dedicated guide there. The release notes for the major version on the repo's GitHub releases page typically link to it. - Release notes: each major version's release notes on the repo's GitHub releases page summarize the breaking changes.
Treat the SDK repo's docs as authoritative. Any version-specific diff written here would drift out of date. The platform file under platforms/ for your target lists the exact repo to consult.
Plan then migrate
Work in this order on every platform:
1. Bump the SDK to the new major version in a branch. 2. Fix compile errors using the CHANGELOG deprecations and removals as a guide. 3. Fix runtime behavior by reading the SDK logs on first launch. 4. Run the existing test suite and manual sandbox scenarios before merging.
4. Implementation
Read the platform file that matches detection:
platforms/ios.mdplatforms/android.mdplatforms/kmp.mdplatforms/flutter.mdplatforms/react-native.md
Each platform file covers both migration paths for that platform.
5. Verify
Do not declare migration done until:
1. The app builds on the new SDK version with no warnings from deprecated APIs you care about. 2. A sandbox purchase succeeds and the transaction shows up on the RevenueCat dashboard Sandbox view with the expected appUserID. 3. An existing subscriber from before the migration opens the app, and their entitlement state is correct. For Path A this proves the observer mode ingest worked. For Path B this proves the version bump did not drop state. 4. You have removed the debug log level override before shipping.
revenuecat-migrate: Android (native Kotlin/Java)
Covers two paths: adopting RevenueCat in an app that already uses Google Play Billing Library directly, and upgrading the RevenueCat SDK across a major version.
Always check CHANGELOG.md in the installed version of purchases-android. The SDK's CHANGELOG is the authoritative source when specifics conflict with this file.
Path A: adopt RevenueCat with existing Play Billing code
Use observer mode. Your existing Play Billing code keeps owning the purchase flow and keeps acknowledging purchases.
Install the SDK
See integrate-revenuecat/platforms/android.md for dependency specifics. Target a recent 8.x or newer release.
Configure in observer mode
import com.revenuecat.purchases.LogLevel
import com.revenuecat.purchases.Purchases
import com.revenuecat.purchases.PurchasesAreCompletedBy
import com.revenuecat.purchases.PurchasesConfiguration
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Purchases.logLevel = LogLevel.DEBUG
Purchases.configure(
PurchasesConfiguration.Builder(this, "goog_YOUR_PUBLIC_SDK_KEY")
.purchasesAreCompletedBy(PurchasesAreCompletedBy.MY_APP)
.build()
)
}
}In observer mode, RevenueCat does not acknowledge purchases. Your existing code must continue to call BillingClient.acknowledgePurchase(...) (or consumePurchase for consumables) within 3 days. If you forget, Play refunds the charge.
Tie existing users to RevenueCat
After login:
Purchases.sharedInstance.logIn(appUserID, callback)This attaches past Play Billing purchases to the right RevenueCat user as transactions are ingested.
Verify observer mode
Run the app, trigger a sandbox purchase using your existing code with a license tester account installed from the Internal Testing track. The transaction should appear on the RevenueCat dashboard Sandbox view within seconds, attached to the right appUserID.
Cutover to full RevenueCat mode (optional, later)
Once observer mode is stable:
1. Remove .purchasesAreCompletedBy(PurchasesAreCompletedBy.MY_APP) from the builder. REVENUECAT is the default. 2. Replace Play Billing purchase calls with Purchases.sharedInstance.purchase(...). 3. Remove your acknowledgePurchase code. RevenueCat now handles it.
Do not ship a build where both the app and RevenueCat try to acknowledge the same purchase.
Path B: upgrade the RevenueCat SDK major version
Major version upgrades change configuration shape, drop deprecated APIs, and shift default behavior in ways that move with each release. This skill does not duplicate the per-version diff. Read the canonical sources from the SDK repo:
- CHANGELOG: <https://github.com/RevenueCat/purchases-android/blob/main/CHANGELOG.md>. Walk entries from your installed version up to the target.
- Migration guides: search the repo for files matching
*MIGRATION*.mdor amigrations/directory; major bumps usually ship a dedicated guide there. The release notes for the major version on <https://github.com/RevenueCat/purchases-android/releases> typically link to it. - Release notes: each major version's release notes on the GitHub releases page summarize the breaking changes.
Treat the SDK repo's docs as authoritative. Any version-specific diff written here would drift out of date.
Verify
After migration:
1. App builds at the new SDK version with Purchases.logLevel = LogLevel.DEBUG. 2. Logcat at launch shows Purchases: ℹ️ [Purchases] - INFO: 😻👼 Purchases is configured. 3. A sandbox purchase from a license tester on the Internal Testing track shows on the RevenueCat dashboard Sandbox view, attached to the correct appUserID. 4. A user with an existing active subscription still has it after relaunch. 5. Log level is dropped before the next release.
revenuecat-migrate: Flutter
Covers two paths: adopting RevenueCat in a Flutter app that already has in app purchases (typically via in_app_purchase or a custom MethodChannel wrapper), and upgrading purchases_flutter across a major version.
Always check the CHANGELOG in the installed version of purchases_flutter. purchases_flutter major bumps typically correspond to purchases-ios / purchases-android major bumps, so the underlying native CHANGELOGs also apply.
Path A: adopt RevenueCat with existing in app purchase code
Use observer mode. Your existing purchase code (whether Dart based or native via in_app_purchase) keeps owning the purchase flow.
Install
Add purchases_flutter to pubspec.yaml and run flutter pub get. See integrate-revenuecat/platforms/flutter.md for the setup details.
Configure in observer mode
import 'dart:io';
import 'package:purchases_flutter/purchases_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Purchases.setLogLevel(LogLevel.debug);
final apiKey = Platform.isIOS
? 'appl_YOUR_IOS_PUBLIC_SDK_KEY'
: 'goog_YOUR_ANDROID_PUBLIC_SDK_KEY';
final config = PurchasesConfiguration(apiKey)
..purchasesAreCompletedBy = const PurchasesAreCompletedByMyApp(
storeKitVersion: StoreKitVersion.storeKit2,
);
await Purchases.configure(config);
runApp(const MyApp());
}Pick StoreKitVersion.storeKit1 if your existing iOS code uses StoreKit 1. The setting only affects the iOS side; Android ignores it.
In observer mode:
- iOS: your StoreKit code must continue to finish transactions.
- Android: your Play Billing code must continue to acknowledge purchases within 3 days.
Tie existing users
await Purchases.logIn(existingAppUserID);Call this after your app's authentication completes.
Cutover to full RevenueCat mode (optional, later)
Remove the purchasesAreCompletedBy assignment. Default is PurchasesAreCompletedByRevenueCat. Replace your purchase code with Purchases.purchasePackage(...) or Purchases.purchaseStoreProduct(...). Remove your own transaction finishing / acknowledgement code at the same time.
Path B: upgrade purchases_flutter across a major version
Major version upgrades change configuration shape, drop deprecated APIs, and shift default behavior in ways that move with each release. This skill does not duplicate the per-version diff. Read the canonical sources from the SDK repo:
- CHANGELOG: <https://github.com/RevenueCat/purchases-flutter/blob/main/CHANGELOG.md>. Walk entries from your installed version up to the target.
- Migration guides: search the repo for files matching
*MIGRATION*.mdor amigrations/directory; major bumps usually ship a dedicated guide there. The release notes for the major version on <https://github.com/RevenueCat/purchases-flutter/releases> typically link to it. - Release notes: each major version's release notes on the GitHub releases page summarize the breaking changes.
Treat the SDK repo's docs as authoritative. Any version-specific diff written here would drift out of date.
Verify
After migration:
1. flutter run builds on both iOS and Android. 2. Xcode console (iOS) shows [Purchases] - INFO: 😻👼 Purchases is configured. Logcat (Android) shows Purchases: ℹ️ [Purchases] - INFO: 😻👼 Purchases is configured. 3. A sandbox purchase on each platform shows on the RevenueCat dashboard Sandbox view with the right appUserID. 4. A user with a pre migration active subscription still shows that entitlement active. 5. await Purchases.setLogLevel(LogLevel.info); before shipping.
revenuecat-migrate: iOS (native)
Covers two paths: adopting RevenueCat in an app that already uses StoreKit, and upgrading the RevenueCat SDK across a major version.
Always check the CHANGELOG.md in the installed version of purchases-ios. The SDK's migration guide (shipped as DocC in the repo under Sources/DocCDocumentation) is the authoritative source when specifics conflict with this file.
Path A: adopt RevenueCat with existing StoreKit code
Use observer mode. Your existing StoreKit code keeps owning the purchase flow.
Install the SDK
See integrate-revenuecat/platforms/ios.md for dependency manager specifics. You want a recent 5.x release.
Configure in observer mode
Pick the StoreKit version your app already uses.
If the app uses StoreKit 1 (SKPaymentQueue, SKProduct, SKPaymentTransaction):
import RevenueCat
Purchases.logLevel = .debug
Purchases.configure(
with: Configuration.Builder(withAPIKey: "appl_YOUR_PUBLIC_SDK_KEY")
.with(purchasesAreCompletedBy: .myApp, storeKitVersion: .storeKit1)
.build()
)If the app uses StoreKit 2 (Product, Transaction, async/await):
Purchases.configure(
with: Configuration.Builder(withAPIKey: "appl_YOUR_PUBLIC_SDK_KEY")
.with(purchasesAreCompletedBy: .myApp, storeKitVersion: .storeKit2)
.build()
)In observer mode, RevenueCat does not call SKPaymentQueue.default().finishTransaction(_:) on your behalf, and does not call Transaction.finish() for StoreKit 2. Keep your existing finishing code in place.
Tie existing users to RevenueCat
If your app has a user ID after login:
try await Purchases.shared.logIn(appUserID)This attaches the StoreKit purchases already associated with the device to the right RevenueCat user as transactions stream in.
Verify observer mode is working
Build and run. Trigger a sandbox purchase with your existing code. In the RevenueCat dashboard Sandbox view, the transaction should appear within a few seconds, attached to the appUserID you logged in with.
Cutover to full RevenueCat mode (optional, later)
Once observer mode is stable in production, you can migrate purchase code to RevenueCat:
1. Remove the .with(purchasesAreCompletedBy: ...) call from the configuration. The default is RevenueCat completed. 2. Replace your StoreKit purchase code with Purchases.shared.purchase(product:) or Purchases.shared.purchase(package:). 3. Remove your own transaction finishing code. RevenueCat now owns this.
Do not ship an interim build where both sides try to finish transactions.
Path B: upgrade the RevenueCat SDK major version
Major version upgrades change configuration shape, drop deprecated APIs, and shift default behavior in ways that move with each release. This skill does not duplicate the per-version diff. Read the canonical sources from the SDK repo:
- CHANGELOG: <https://github.com/RevenueCat/purchases-ios/blob/main/CHANGELOG.md>. Walk entries from your installed version up to the target.
- Migration guides: search the repo for files matching
*MIGRATION*.mdor amigrations/directory; major bumps usually ship a dedicated guide there. The release notes for the major version on <https://github.com/RevenueCat/purchases-ios/releases> typically link to it. - Release notes: each major version's release notes on the GitHub releases page summarize the breaking changes.
Treat the SDK repo's docs as authoritative. Any version-specific diff written here would drift out of date.
Verify
After migration:
1. App builds with Purchases.logLevel = .debug. 2. Xcode console shows [Purchases] - INFO: 😻👼 Purchases is configured at launch. 3. A fresh sandbox purchase shows on the RevenueCat dashboard Sandbox view. 4. A user who had an active subscription before the upgrade still shows that entitlement active. 5. Debug log level is removed before the next release build.
revenuecat-migrate: Kotlin Multiplatform
purchases-kmp wraps purchases-ios and purchases-android. Migration on KMP is a thin shim over platform native migration, so the platform files revenuecat-migrate/platforms/ios.md and revenuecat-migrate/platforms/android.md remain the source of truth.
Path A: adopt RevenueCat with existing native IAP code
If the app has existing StoreKit or Play Billing code under each platform's native source set, follow the observer mode setup in ios.md and android.md. The shared KMP entry point just passes the flag through.
Configure in observer mode from shared code
Expected shape (check the installed version of purchases-kmp-core; its expect/actual surface has changed across releases):
import com.revenuecat.purchases.kmp.LogLevel
import com.revenuecat.purchases.kmp.Purchases
import com.revenuecat.purchases.kmp.PurchasesAreCompletedBy
import com.revenuecat.purchases.kmp.PurchasesConfiguration
fun initRevenueCat(apiKey: String) {
Purchases.logLevel = LogLevel.DEBUG
Purchases.configure(
PurchasesConfiguration.Builder(apiKey = apiKey)
.purchasesAreCompletedBy(PurchasesAreCompletedBy.MY_APP)
.build()
)
}If PurchasesAreCompletedBy or the builder method name differs in your installed version, rely on the IDE's autocomplete over this file. The KMP wrapper's type names track the native names but are occasionally renamed to kmp-friendly equivalents.
StoreKit version on iOS
On the iOS side, observer mode still requires explicit storeKitVersion selection. If your existing iOS code uses StoreKit 1, pass that version through. If StoreKit 2, pass that. The KMP SDK forwards the selection to purchases-ios.
Acknowledgement on Android
On Android, observer mode still means your own code must acknowledge purchases within 3 days. The KMP wrapper does not change this.
Tie existing users
Call Purchases.logIn(appUserID) from shared code after the user is known.
Path B: upgrade the SDK major version
Major version upgrades change configuration shape, drop deprecated APIs, and shift default behavior in ways that move with each release. This skill does not duplicate the per-version diff. Read the canonical sources from the SDK repo:
- CHANGELOG: <https://github.com/RevenueCat/purchases-kmp/blob/main/CHANGELOG.md>. Walk entries from your installed version up to the target.
- Migration guides: search the repo for files matching
*MIGRATION*.mdor amigrations/directory; major bumps usually ship a dedicated guide there. The release notes for the major version on <https://github.com/RevenueCat/purchases-kmp/releases> typically link to it. - Release notes: each major version's release notes on the GitHub releases page summarize the breaking changes.
Treat the SDK repo's docs as authoritative. Any version-specific diff written here would drift out of date.
Verify
After migration:
1. Both iOS and Android targets build at the new version with debug logging on. 2. The native SDK configure banner appears in each target's platform console. 3. A sandbox purchase on each target shows on the RevenueCat dashboard. 4. An existing subscriber still has their entitlement active on each target. 5. Log level dropped before release.
revenuecat-migrate: React Native
Covers two paths: adopting RevenueCat in a React Native app that already has in app purchases (typically via react-native-iap or a custom native module), and upgrading react-native-purchases across a major version.
Always check the CHANGELOG in the installed version of react-native-purchases. Major bumps of react-native-purchases usually track native SDK major bumps, so the underlying native CHANGELOGs also apply.
Path A: adopt RevenueCat with existing in app purchase code
Use observer mode. Your existing purchase code (JS or native module) keeps owning the purchase flow.
Install
npm install react-native-purchases
cd ios && pod install && cd ..For Expo managed projects:
npx expo install react-native-purchases
npx expo prebuild --clean # dev client required, Expo Go does not workConfigure in observer mode
import { Platform } from 'react-native';
import Purchases, {
LOG_LEVEL,
PURCHASES_ARE_COMPLETED_BY_TYPE,
STOREKIT_VERSION,
} from 'react-native-purchases';
Purchases.setLogLevel(LOG_LEVEL.DEBUG);
const apiKey = Platform.OS === 'ios'
? 'appl_YOUR_IOS_PUBLIC_SDK_KEY'
: 'goog_YOUR_ANDROID_PUBLIC_SDK_KEY';
Purchases.configure({
apiKey,
purchasesAreCompletedBy: {
type: PURCHASES_ARE_COMPLETED_BY_TYPE.MY_APP,
storeKitVersion: STOREKIT_VERSION.STOREKIT_2,
},
});Pass STOREKIT_VERSION.STOREKIT_1 if your existing iOS code uses StoreKit 1. The setting only affects the iOS side.
In observer mode:
- iOS: your StoreKit code must continue to finish transactions.
- Android: your Play Billing code must continue to acknowledge purchases within 3 days.
Tie existing users
await Purchases.logIn(existingAppUserID);Cutover to full RevenueCat mode (optional, later)
Drop the purchasesAreCompletedBy field from the configure call (the default is REVENUECAT). Replace your purchase code with Purchases.purchasePackage(...) or Purchases.purchaseStoreProduct(...). Remove your own transaction finishing / acknowledgement code at the same time.
Path B: upgrade react-native-purchases across a major version
Major version upgrades change configuration shape, drop deprecated APIs, and shift default behavior in ways that move with each release. This skill does not duplicate the per-version diff. Read the canonical sources from the SDK repo:
- CHANGELOG: <https://github.com/RevenueCat/react-native-purchases/blob/main/CHANGELOG.md>. Walk entries from your installed version up to the target.
- Migration guides: search the repo for files matching
*MIGRATION*.mdor amigrations/directory; major bumps usually ship a dedicated guide there. The release notes for the major version on <https://github.com/RevenueCat/react-native-purchases/releases> typically link to it. - Release notes: each major version's release notes on the GitHub releases page summarize the breaking changes.
Treat the SDK repo's docs as authoritative. Any version-specific diff written here would drift out of date.
Verify
After migration:
1. App builds and launches on both iOS and Android. 2. Native platform console (Xcode / logcat) shows the Purchases is configured banner. 3. A sandbox purchase on each platform shows on the RevenueCat dashboard Sandbox view with the right appUserID. 4. A user with a pre migration active subscription still shows that entitlement active. 5. Purchases.setLogLevel(LOG_LEVEL.INFO); before shipping.