Build With RevenueCat

Build a customized mobile subscription business with RevenueCat. We do the heavy lifting of normalizing subscribers from any source and maintain a single source of truth for subscription status, so you can get back to building your app.

RevenueCat is a powerful, secure, reliable, and free to use in-app purchase server with global support. All you need to get started is an API key.

Get Started    API Reference

Subscription Status

Determining the subscription status for a user.

RevenueCat makes it easy to determine subscription status and more with the Purchases SDK and REST API.

Get User Information

The PurchaserInfo object contains all of the purchase and subscription data available about the user. This object is updated whenever a purchase or restore occurs and periodically throughout the lifecycle of your app. The latest information can always be retrieved by calling getPurchaserInfo():

Purchases.shared.purchaserInfo { (purchaserInfo, error) in
    // access latest purchaserInfo
}
[[RCPurchases sharedPurchases] purchaserInfoWithCompletionBlock:^(RCPurchaserInfo * purchaserInfo, NSError * error) {
     // access latest purchaserInfo
}];
Purchases.sharedInstance.getPurchaserInfoWith({ error -> /* Optional error handling */ }) { purchaserInfo ->
  // access latest purchaserInfo
}
Purchases.getSharedInstance().getPurchaserInfo(new ReceivePurchaserInfoListener() {
  @Override
  public void onReceived(@NonNull PurchaserInfo purchaserInfo) {
    // access latest purchaserInfo
  }
  
  @Override
  public void onError(@NonNull PurchasesError error) {

  }
});
try {
  PurchaserInfo purchaserInfo = await Purchases.getPurchaserInfo();
  // access latest purchaserInfo
} on PlatformException catch (e) {
  // Error fetching purchaser info
}
try {
  const purchaserInfo = await Purchases.getPurchaserInfo();
  // access latest purchaserInfo
} catch (e) {
 // Error fetching purchaser info
}
Purchases.getPurchaserInfo(
  purchaserInfo => {
     // access latest purchaserInfo
  },
  error => {
    // Error fetching purchaser info
  }
);
var purchases = GetComponent<Purchases>();
purchases.GetPurchaserInfo((purchaserInfo, error) =>
{
  // access latest purchaserInfo
});

It's safe to call getPurchaserInfo() frequently throughout your app. Since the Purchases SDK updates and caches the latest PurchaserInfo when the app becomes active, the completion block won't need to make a network request in most cases.

📘

Working with the cache

The SDK caches the user's subscription information to reduce your app's reliance on the network. Users who unlock entitlements will be able to access them even without an internet connection. The SDK will update the cache if it's older than 5 minutes, but only if you call getPurchaserInfo(), make a purchase, or restore purchases, so it's a good idea to call getPurchaserInfo() any time a user accesses premium content.

The PurchaserInfo object gives you access to the following information about a user:

Name

Description

Request Date

The server date when the current PurchaserInfo object was fetched. This should be used for date comparison operators instead of relying on the device time.

Original App User Id

The original app user id recorded for this user. May be the same as their current app user id. See our guide on user ids for more information.

First Seen

The date this user was first seen in RevenueCat. This is the install date in most cases

Original Application Version

iOS only. The version number for the first version of the app this user downloaded. Will be nil unless a receipt has been recorded for the user through a purchase, restore, or import.

Note in sandbox this will always be "1.0"

Management URL

URL to manage the active subscription of the user. If the user has an active iOS subscription, this will point to the App Store, if the user has an active Play Store subscription it will point there.

If there are no active subscriptions it will be null.

If there are multiple for different platforms, it will point to the App Store

All Purchased Product Identifiers

An array of product identifiers purchased by the user regardless of expiration.

Non Consumable Purchases

An array of all the non-consumable product identifiers purchased by the user.

Active Subscriptions

An array of subscription product identifiers that are active. You should be using entitlement though.

Entitlements

EntitlementInfo objects that contain information about the user's entitlements, such as subscription state. See more below.

Get Entitlement Information

The EntitlementInfo object gives you access to all of the information about the status of a users entitlements.

Name

Description

Identifier

The entitlement identifier configured in the RevenueCat dashboard.

Product Identifier

The underlying product identifier that unlocked this entitlement.

Is Active

Whether or not the user has access to this entitlement.

Will Renew

Whether or not the entitlement is set to renew at the end of the current period.

Note there may be a multiple hour delay between the value of this property and the actual state in the App Store / Play Store.

Period Type

The period type this entitlement is in, can be one of:

  • Trial: In a free trial period
  • Intro: In an introductory price period
  • Normal: In the default period

Latest Purchase Date

The latest purchase or renewal date for this entitlement.

Original Purchase Date

The first date this entitlement was purchased. May be the same as the latest purchase date.

Expiration Date

The expiration date for the entitlement, can be null for lifetime access. If the period type is trial then this is the trial expiration date.

Store

The store that unlocked this entitlement, can be one of:

  • App Store
  • Mac App Store
  • Play Store
  • Stripe
  • Promotional (RevenueCat)

Is Sandbox

Whether this entitlement was unlocked from a sandbox or production purchase.

Unsubscribe Detected At

The date an unsubscribe was detected. An unsubscribe does not mean that the entitlement is inactive.

Note there may be a multiple hour delay between the value of this property and the actual state in the App Store / Play Store.

Billing Issue Detected At

The date a billing issue was detected, will be null again once billing issue resolved. A billing issue does not mean that the entitlement is inactive.

Note there may be a multiple hour delay between the value of this property and the actual state in the App Store / Play Store.

Checking If A User Is Subscribed

The subscription status for a user can easily be determined with the PurchaserInfo and EntitlementInfo objects.

For most apps that only have one entitlement, the isActive status can be quickly checked for your entitlement Id.

if purchaserInfo.entitlements["your_entitlement_id"]?.isActive == true {
  // user has access to "your_entitlement_id"                
}
if (purchaserInfo.entitlements[@"your_entitlement_id"].isActive) {
  // user has access to "your_entitlement_id"
}
if (purchaserInfo.entitlements["your_entitlement_id"]?.isActive == true) {
    // user has access to "your_entitlement_id"                
}
if (purchaserInfo.getEntitlements().get("your_entitlement_id").isActive()) {
    // user has access to "your_entitlement_id"
}
if (purchaserInfo.entitlements.all["my_entitlement_identifier"].isActive) {
  // Grant user "pro" access
}
if(typeof purchaserInfo.entitlements.active.my_entitlement_identifier !== "undefined") {
  // Grant user "pro" access
}
if(typeof purchaserInfo.entitlements.active.my_entitlement_identifier !== "undefined") {
  // Grant user "pro" access
}
if (purchaserInfo.Entitlements.Active.ContainsKey("my_entitlement_identifier")) {
  // Unlock that great "pro" content
}

If your app has multiple entitlements and you need to check if a user is subscribed to at least one you can also check for the entitlement Id in the active dictionary of EntitlementInfo objects.

if !purchaserInfo.entitlements.active.isEmpty {
    //user has access to some entitlement
}
if ([purchaserInfo.entitlements.active count] > 0) {
    //user has access to some entitlement
}
if (purchaserInfo.entitlements.active.isNotEmpty()) {
  //user has access to some entitlement
}
if (!purchaserInfo.getEntitlements().getActive().isEmpty()) {
    //user has access to some entitlement
}
if (purchaserInfo.entitlements.active.isNotEmpty) {
  //user has access to some entitlement
}
if (Object.entries(purchaserInfo.entitlements.active).length) {
  //user has access to some entitlement
}
if (Object.entries(purchaserInfo.entitlements.active).length) {
  //user has access to some entitlement
}
if (purchaserInfo.Entitlements.Active.Count != 0) {
    //user has access to some entitlement
}

It's important to note that PurchaserInfo will be empty if no purchases have been made and no transactions have been synced. This means that entitlements may not exist in PurchaserInfo even if they have been set up in the RevenueCat dashboard.

Listening For Purchaser Info Updates

Since Purchases SDK works seamlessly on any platform, a user's purchase info may change from a variety of sources. You can respond to any changes in purchaser info by conforming to an optional delegate method, didReceivePurchaserInfo:. This will fire whenever we receive a change in purchaser info on the current device and you should expect it to be called at launch and throughout the life of the app.

Depending on your app, it may be sufficient to ignore the delegate and simply handle changes to purchaser information the next time your app is launched. Or throughout your app as you request new PurchaserInfo objects.

extension AppDelegate: PurchasesDelegate {
    func purchases(_ purchases: Purchases, didReceiveUpdated purchaserInfo: Purchases.PurchaserInfo) {
        // handle any changes to purchaserInfo
    }
}
- (void)purchases:(nonnull RCPurchases *)purchases didReceiveUpdatedPurchaserInfo:(nonnull RCPurchaserInfo *)purchaserInfo {
    // handle any changes to purchaserInfo
}
class UpsellActivity : AppCompatActivity(), UpdatedPurchaserInfoListener {
  override fun onReceived(purchaserInfo: PurchaserInfo) {
    // handle any changes to purchaserInfo
  }
  
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    Purchases.sharedInstance.updatedPurchaserInfoListener = this
  }   
}
public class UpsellActivity extends AppCompatActivity implements UpdatedPurchaserInfoListener {
  @Override public void onReceived(PurchaserInfo purchaserInfo) {
    // handle any changes to purchaserInfo
  } 
  
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
Purchases.getSharedInstance().setUpdatedPurchaserInfoListener(this);
  }   
}
Purchases.addPurchaserInfoUpdateListener((info) {
    // handle any changes to purchaserInfo
});
Purchases.addPurchaserInfoUpdateListener((info) => {
    // handle any changes to purchaserInfo
});
window.addEventListener("onPurchaserInfoUpdated", (info) => {
    // handle any changes to purchaserInfo
});
public class PurchasesListener : Purchases.UpdatedPurchaserInfoListener
{
    public override void PurchaserInfoReceived(Purchases.PurchaserInfo purchaserInfo)
    {
       // handle any changes to purchaserInfo
    }
}

Web Apps

If you also have a web app, or need to get a user's subscription status from outside of the Purchases SDK, you should use the REST API. You can read the full API reference here.

curl --request GET \
  --url https://api.revenuecat.com/v1/subscribers/app_user_id \
  --header 'content-type: application/json'

Next Steps

Updated 8 days ago


Subscription Status


Determining the subscription status for a user.

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.