syncPurchases() in RevenueCat: When and How to Use It

Overview

syncPurchases() is the RevenueCat method that makes RevenueCat aware of purchases it did not process itself. It reads the current purchase state from the store (App Store or Google Play) and syncs it to the user's RevenueCat record, returning an updated CustomerInfo.

The short answer most people are looking for: in a standard RevenueCat integration you almost never call syncPurchases() yourself. The SDK already syncs purchases automatically. The method exists mainly for observer mode, where another in-app purchase library makes the purchase and RevenueCat only observes (it does not make the purchase). In that setup you call syncPurchases() so RevenueCat learns about purchases it did not handle.

Quick rule: if RevenueCat makes your purchases (the normal setup), do not call syncPurchases(). If another library makes the purchases (observer mode), call it after that library completes a transaction.
Prerequisites: The RevenueCat SDK must already be installed and configured with Purchases.configure(...). See the React Native codelab and the Configure the SDK guide for setup.

What syncPurchases Does

When you call syncPurchases(), the SDK collects the purchase information available from the underlying store and posts it to RevenueCat's backend. RevenueCat then re-evaluates the user's entitlements and returns a fresh CustomerInfo that reflects any purchases it just learned about.

  • It informs RevenueCat of purchases that another SDK or process completed.
  • It returns an updated CustomerInfo so you can read the user's current entitlements.
  • It is not user-facing: there is no button or user gesture tied to it.
  • It does not perform the account-transfer logic that restorePurchases() does.

In a normal RevenueCat integration, the SDK already detects and syncs purchases automatically, so the updated CustomerInfo flows to you without an explicit call. That is why this method is so rarely needed outside observer mode.

syncPurchases vs restorePurchases

These two methods are frequently confused because both end up updating CustomerInfo, but they serve different roles. restorePurchases() is the user-initiated action you tie to a "Restore Purchases" button; syncPurchases() is a background sync used mostly in observer mode.

Aspect syncPurchases() restorePurchases()
Who triggers it Automatic / observer mode (no button) The user, via a "Restore Purchases" button
Purpose Tell RevenueCat about purchases it did not process Let a user recover purchases on a new install or device
Account transfer No (does not transfer entitlements between accounts) Yes (can transfer entitlements between accounts)
App Store requirement Not a user-facing feature, not required A "Restore Purchases" action is required by App Store guidelines

If you are looking for the button users tap to recover their subscriptions, you want restorePurchases(), not syncPurchases(). See the platform restore guides: React Native, iOS, and Android.

Observer Mode (The Main Use Case)

Observer mode is the one setup where syncPurchases() is genuinely needed. In observer mode, RevenueCat does not make purchases. Another in-app purchase library (your own billing code, or a different SDK) completes the transaction, and RevenueCat simply observes to power its analytics, charts, and integrations.

Because RevenueCat is not the one finishing the transaction, it will not automatically know about the purchase. After the other library reports a successful purchase, you call syncPurchases() so RevenueCat reads the store state and records the purchase against the current user.

The typical observer-mode flow: (1) your other IAP library completes a purchase, (2) its success callback fires, (3) you call syncPurchases(), (4) RevenueCat picks up the purchase and returns an updated CustomerInfo you can use to unlock content.

See the official RevenueCat docs for how to enable observer mode at configuration time on each platform.

Code Per Platform

The examples below show how to call syncPurchases() on each platform. Call these only in observer mode, after the other purchase library has completed a transaction.

React Native

typescript
import Purchases, { CustomerInfo } from 'react-native-purchases';

// Observer mode: call this AFTER your other IAP library completes a purchase.
async function syncAfterExternalPurchase(): Promise<void> {
  try {
    const customerInfo: CustomerInfo = await Purchases.syncPurchases();
    const isPro = typeof customerInfo.entitlements.active['premium'] !== 'undefined';
    console.log('Synced purchases. Pro active?', isPro);
  } catch (e) {
    console.error('syncPurchases failed', e);
  }
}

iOS (Swift)

swift
import RevenueCat

// Observer mode: call this AFTER your other IAP code finishes a transaction.
func syncAfterExternalPurchase() async {
    do {
        let customerInfo = try await Purchases.shared.syncPurchases()
        let isPro = customerInfo.entitlements["premium"]?.isActive == true
        print("Synced purchases. Pro active? \(isPro)")
    } catch {
        print("syncPurchases failed: \(error)")
    }
}

Android (Kotlin, coroutines)

kotlin
// Observer mode: call this AFTER your other IAP library completes a purchase.
viewModelScope.launch {
    try {
        val customerInfo = Purchases.sharedInstance.awaitSyncPurchases()
        val isPro = customerInfo.entitlements["premium"]?.isActive == true
        Log.d("Purchases", "Synced purchases. Pro active? $isPro")
    } catch (e: PurchasesException) {
        Log.e("Purchases", "syncPurchases failed: ${e.message}")
    }
}

Android (Kotlin, callback)

kotlin
Purchases.sharedInstance.syncPurchases(
    object : SyncPurchasesCallback {
        override fun onSuccess(customerInfo: CustomerInfo) {
            val isPro = customerInfo.entitlements["premium"]?.isActive == true
            Log.d("Purchases", "Synced purchases. Pro active? $isPro")
        }

        override fun onError(error: PurchasesError) {
            Log.e("Purchases", "syncPurchases failed: ${error.message}")
        }
    }
)

When NOT to Call syncPurchases()

Do not call it in a standard integration. If RevenueCat makes your purchases (the normal setup with purchase(...) or the paywall), the SDK syncs automatically. Calling syncPurchases() yourself is redundant and adds unnecessary network requests.
Do not use it as a "Restore Purchases" button. That is what restorePurchases() is for. restorePurchases() is user-initiated, can transfer entitlements between accounts, and satisfies App Store requirements. syncPurchases() does not transfer accounts and is not a user-facing feature.
Do not call it on every app launch. Even in observer mode, call it in response to a completed external purchase, not blindly on startup. Repeated calls add load without changing the result once the purchase is already synced.

FAQ

What does syncPurchases() do?
It tells RevenueCat about purchases it did not process itself, reads the store's purchase state, syncs it to the user's RevenueCat record, and returns an updated CustomerInfo. In a normal integration the SDK does this automatically, so you rarely call it.

What is the difference between syncPurchases() and restorePurchases()?
restorePurchases() is the user-initiated action behind a "Restore Purchases" button; it can transfer entitlements between accounts and is required by the App Store. syncPurchases() is not user-facing, needs no button, does not transfer accounts, and is used mostly in observer mode to inform RevenueCat of purchases made by another SDK.

When should I call syncPurchases()?
In observer mode, right after another in-app purchase library completes a transaction, so RevenueCat can pick it up. In a standard integration you normally never call it.

Do I need to call it after every purchase?
No. In a normal integration the SDK syncs automatically. Only call it in observer mode after the other purchase library finishes a transaction.

Related Guides