Skip to main content
Answer

Restoring Previous Purchases with RevenueCat in TestFlight After Migrating from SwiftyStoreKit

  • October 2, 2025
  • 4 replies
  • 72 views

Forum|alt.badge.img+3

I previously implemented the subscription feature using SwiftyStoreKit, and all receipts were processed locally only. Recently, I applied RevenueCat and implemented a custom paywall. The implementation is complete, and I am currently testing it in TestFlight.

In the TestFlight environment, I was able to restore purchases from my actual App Store account with the old setup, but with the RevenueCat SDK, restoration does not work. Is this the expected behavior? I am worried that existing users may not be able to restore their purchases when the app is released on the App Store.

Purchases.shared.syncPurchases()

For receipt migration, I executed the above code once to synchronize existing purchase history. I understand that server-side synchronization of previous purchases is recommended, but since there is no existing backend history, I cannot use that method. In this state, if I release the app on the App Store, will existing users be able to safely restore their past purchases?

Best answer by guilherme

Hey ​@dkjack ,

Thanks for reaching out!To help diagnose this, could you provide:

  1. A few App User IDs where you're seeing restoration fail (you can find these in the RevenueCat dashboard or SDK logs)
  2. SDK debug logs for the restore attempt - enable debug logs and share what you see when a user tries to restore

You mentioned using syncPurchases() - here's how that compares to restorePurchases():

syncPurchases()

  • sends the current device's App Store receipt to RevenueCat
  • only syncs purchases for whoever is currently logged into the App Store on that device
  • good for one-time migration tasks

More context here

 

restorePurchases()

  • does everything syncPurchases() does, plus links the current user to any previous RevenueCat user who owned these same purchases
  • this is what you want users to call when they tap "Restore Purchases" in your app
  • handles the "I reinstalled the app" or "I'm on a new device" scenarios

More context here

Since you're migrating from SwiftyStoreKit (where RevenueCat hasn't seen these purchases before), you should use restorePurchases() instead of syncPurchases(). This ensures RevenueCat properly links the purchases to the user's account.

We recommend that the restorePurchases() action, since it should be User started, should live inside a Paywall or/and from your own (e.g Setting) app screen.

TestFlight uses Apple's sandbox environment, which can behave differently than production:

  • If you purchased a subscription in a production version of your app, it may not appear when testing in TestFlight (different environments)
  • For testing, make a fresh subscription purchase within TestFlight itself, then try restoring 

As for production users being affected, this will most likely no occur - your production users will be in the same environment (production App Store) with the same Apple ID, so restoration should work smoothly. The TestFlight issue you're seeing is probably environment-related.

But feel free to send those over, either here or via our support channel (and link this thread there for extra context too): https://app.revenuecat.com/settings/support?tab=contact 

 

Thanks,

This post has been closed for comments

4 replies

guilherme
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • Answer
  • October 6, 2025

Hey ​@dkjack ,

Thanks for reaching out!To help diagnose this, could you provide:

  1. A few App User IDs where you're seeing restoration fail (you can find these in the RevenueCat dashboard or SDK logs)
  2. SDK debug logs for the restore attempt - enable debug logs and share what you see when a user tries to restore

You mentioned using syncPurchases() - here's how that compares to restorePurchases():

syncPurchases()

  • sends the current device's App Store receipt to RevenueCat
  • only syncs purchases for whoever is currently logged into the App Store on that device
  • good for one-time migration tasks

More context here

 

restorePurchases()

  • does everything syncPurchases() does, plus links the current user to any previous RevenueCat user who owned these same purchases
  • this is what you want users to call when they tap "Restore Purchases" in your app
  • handles the "I reinstalled the app" or "I'm on a new device" scenarios

More context here

Since you're migrating from SwiftyStoreKit (where RevenueCat hasn't seen these purchases before), you should use restorePurchases() instead of syncPurchases(). This ensures RevenueCat properly links the purchases to the user's account.

We recommend that the restorePurchases() action, since it should be User started, should live inside a Paywall or/and from your own (e.g Setting) app screen.

TestFlight uses Apple's sandbox environment, which can behave differently than production:

  • If you purchased a subscription in a production version of your app, it may not appear when testing in TestFlight (different environments)
  • For testing, make a fresh subscription purchase within TestFlight itself, then try restoring 

As for production users being affected, this will most likely no occur - your production users will be in the same environment (production App Store) with the same Apple ID, so restoration should work smoothly. The TestFlight issue you're seeing is probably environment-related.

But feel free to send those over, either here or via our support channel (and link this thread there for extra context too): https://app.revenuecat.com/settings/support?tab=contact 

 

Thanks,


Forum|alt.badge.img+3
  • Author
  • New Member
  • October 13, 2025

Thank you for your response. I have a few additional questions.

Previously, I was using SwiftyStoreKit, and I am now migrating to RevenueCat. To maintain the paid status of existing subscribers, I used the following code to perform a one-time migration when the updated version with RevenueCat is launched for the first time:

 

let customerInfo: CustomerInfo
if hasRunRevenueCatMigration() {
customerInfo = try await Purchases.shared.customerInfo()
} else {
customerInfo = try await Purchases.shared.syncPurchases()
setHasRunRevenueCatMigration()
}

 

In your previous comment, you mentioned that when using SwiftyStoreKit, it’s better to use restorePurchases() instead of syncPurchases().
However, when I use restorePurchases(), a login prompt appears asking the user to sign in, which results in a poor user experience.

According to the documentation, when synchronizing existing user information locally, syncPurchases() should be used.
Do I really need to use restorePurchases() instead?
To clarify, my question is specifically about users who are not reinstalling the app — those who have already been using it and still have a valid receipt stored on their device.


guilherme
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • October 20, 2025

Hey ​@dkjack!

For users who already have the app installed with a valid receipt on their device, syncPurchases() will indeed work as expected - it reads the existing local receipt and sends it to RevenueCat for validation without triggering any OS prompts and is specifically designed for programmatic syncing during migrations.

The key technical difference between the two methods is that restorePurchases() refreshes the receipt from Apple's servers (which can trigger sign-in prompts), while syncPurchases() uses the existing local receipt silently.

Having the syncPurchases() call made once after setting up/authenticating with the SDK should indeed cover your scenario around migrations.

That said, we recommend to still have a "restore purchases" button accessible somewhere in your app (like Settings or your Paywall screen), separate from your migration code. This would be a User own started flow (as in, not automatic without them requesting it) that handles scenarios where users reinstall the app, switch devices, or need to refresh their receipt for any reason - situations where the local receipt might be outdated or missing.


Forum|alt.badge.img+3
  • Author
  • New Member
  • October 22, 2025

Hey ​@guilherme 
Thanks to your help, I was able to successfully launch the app. Thank you.