Identifying Customers

How RevenueCat handles user identity

RevenueCat provides a source of truth for a subscriber's status across different platforms. To do this, each subscriber has an App User ID that uniquely identifies them within your application.

User identity is one of the most important components of many mobile applications, and it's extra important to make sure the subscription status RevenueCat is tracking gets associated with the correct user.

The Purchases SDK allows you to specify your own user identifiers or use anonymous identifiers generated by RevenueCat. Some apps will use a combination of their own identifiers and RevenueCat anonymous IDs - that's okay!

Anonymous App User IDs

If you don't provide an App User ID when instantiating the Purchases SDK, RevenueCat will generate a new random App User ID for you and cache it on the device. In the event that the user deletes and reinstalls the app, a new random App User ID will be generated.

Purchases.configure(withAPIKey: "my_api_key")
[RCPurchases configureWithAPIKey:@"my_api_key"];
Purchases.configure(PurchasesConfiguration.Builder(this, "api_key").build())
Purchases.configure(new PurchasesConfiguration.Builder(context, "api_key").build());
await Purchases.configure(PurchasesConfiguration("public_sdk_key"));
Purchases.configure({apiKey: "public_sdk_key"});
Purchases.setup("public_sdk_key");
// The SDK can be configured through the Unity Editor. 
// See Unity installation instructions https://docs.revenuecat.com/docs/unity

// If you'd like to do it programmatically instead, 
// make sure to check "Use runtime setup" in the Editor and then: 

Purchases.PurchasesConfiguration.Builder builder = Purchases.PurchasesConfiguration.Builder.Init("api_key");
Purchases.PurchasesConfiguration purchasesConfiguration = builder.Build();
purchases.Configure(purchasesConfiguration);

📘

Anonymous App User IDs are always prefixed with $RCAnonymousID: for SDK versions 3+. This can be useful for working with anonymous users on your server.

Logging In with a Custom App User ID

Setting your own App User ID will allow you to reference users in the RevenueCat dashboard, via the API, as well as in the webhooks and other integrations.

Using an externally managed App User ID also provides a mechanism by which to restore purchases in a few scenarios:

  • When a user deletes and reinstalls your app - using the same App User ID will ensure they still have access to subscriptions previously started without requiring a restore .
  • When the user logs in on multiple devices - you can honor a subscription that was purchased on one device across any other platform.

📘

App User IDs are case-sensitive.

Provide App User ID on configuration

❗ī¸

iOS 15+ Prewarming

In certain cases, iOS may prewarm your app - this essentially means your app will be launched silently in the background to improve app launch times for your users.

If you are not using RevenueCat's anonymous IDs as described above, and are instead providing your own app user ID on configuration, do not call configure in application:didFinishLaunchingWithOptions:. Instead, call the configure method in your root view controller's initialization method.

If you have your own App User IDs at app launch, you can pass those on instantiation to Purchases.

Purchases.configure(withAPIKey: "my_api_key", appUserID: "my_app_user_id")
[RCPurchases configureWithAPIKey:@"my_api_key" appUserID:@"my_app_user_id"];
Purchases.configure(PurchasesConfiguration.Builder(this, "api_key").appUserID("my_app_user_id").build())
Purchases.configure(new PurchasesConfiguration.Builder(context, "api_key").appUserID("my_app_user_id").build());
await Purchases.configure(
    PurchasesConfiguration("public_sdk_key")
      ..appUserID = "my_app_user_id"
);
Purchases.configure({apiKey: "public_sdk_key", appUserID: "my_app_user_id"});
Purchases.setup("public_sdk_key", "my_app_user_id");
// The appUserID can be set through the Unity Editor. 
// See Unity installation instructions https://docs.revenuecat.com/docs/unity

// If you'd like to do it programmatically instead, 
// make sure to check "Use runtime setup" in the Editor and then: 

Purchases.PurchasesConfiguration.Builder builder = Purchases.PurchasesConfiguration.Builder.Init("api_key");
Purchases.PurchasesConfiguration purchasesConfiguration =
    builder.SetUserDefaultsSuiteName("user_default")
    .SetDangerousSettings(new Purchases.DangerousSettings(false))
    .SetObserverMode(true)
    .SetUseAmazon(false)
    .SetAppUserId(appUserId)
    .Build();
purchases.Configure(purchasesConfiguration);

Often times, you may not have your own App User IDs until later in the application lifecycle. In these cases, you can pass the App User ID later through the .logIn() method.

Provide App User ID after configuration

If your app doesn't receive its own App User ID until later in its lifecycle, you can set (or change) the App User ID at any time by calling .logIn(). If the logged in identity does not already exist in RevenueCat, it will be created automatically.

// Configure Purchases on app launch
Purchases.configure(withAPIKey: "my_api_key")

//...

// Later log in provided user Id
Purchases.shared.logIn("my_app_user_id") { (customerInfo, created, error) in
    // customerInfo updated for my_app_user_id
}
// Configure Purchases on app launch
[RCPurchases configureWithAPIKey:@"my_api_key"];

//...

// Later log in provided user Id
[[RCPurchases sharedPurchases] logIn:@"my_app_user_id" completion:^(RCCustomerInfo *customerInfo, BOOL created, NSError *error) {
    // purchaserInfo updated for my_app_user_id
}];
// Configure Purchases on app launch
Purchases.configure(PurchasesConfiguration.Builder(this, "api_key").build())
  
//...

// Later log in provided user Id
Purchases.sharedInstance.loginWith("my_app_user_id", ::showError) { customerInfo, created ->
  // customerInfo updated for my_app_user_id
}
// Configure Purchases on app launch
Purchases.configure(new PurchasesConfiguration.Builder(context, "api_key").build());

//...

// Later log in provided user Id
Purchases.getSharedInstance().logIn("my_app_user_id", new LogInCallback() {
    @Override
    public void onReceived(@NotNull CustomerInfo customerInfo, boolean created) {
        // customerInfo updated for my_app_user_id
    }
  
  @Override
  public void onError(@NotNull PurchasesError error) {

  }
});
// Configure Purchases on app launch
await Purchases.configure(PurchasesConfiguration("public_sdk_key"));

//...

// Later log in provided user Id
LogInResult result = await Purchases.logIn("my_app_user_id");
// Configure Purchases on app launch
Purchases.configure({apiKey: "public_sdk_key"});

//...

// Later log in provided user Id
const { purchaserInfo, created } = await Purchases.logIn("my_app_user_id");
// purchaserInfo updated for my_app_user_id
// Configure Purchases on app launch
Purchases.setup("public_sdk_key");

//...

// Later log in provided user Id

Purchases.logIn(
  "my_app_user_id", 
  ({ customerInfo, created }) => {
    // customerInfo updated for my_app_user_id
  },
  error => {
  }
);
// configure the SDK either through the Editor or through 
// programmatic setup (see section above), then:


var purchases = GetComponent<Purchases>();
purchases.LogIn("myAppUserUD", (customerInfo, created, error) =>
{
    if (error != null)
    {
        // show error
    }
    else
    {
        // show customerInfo
    }
});

logIn() method alias behavior

When going from an Anonymous ID to a custom App User ID RevenueCat will decide whether the identities should be merged (aliased) into the same CustomerInfo object or not depending on the state of the custom App User ID and if it already has an anonymous alias.

Current App User IDProvided App User ID already exists?Provided App User ID has anonymous alias?Result
AnonymousNoN/AAnonymous ID is aliased with Provided ID, CustomerInfo merged.
AnonymousYesNoAnonymous ID is aliased with Provided ID, CustomerInfo merged.
AnonymousYesYesCustomerInfo changes to Provided ID, no aliases created.
Non-anonymousAnyAnyCustomerInfo changes to Provided ID, no aliases created.

Logging Out

When an identified user logs out you should call the logOut() method - this generates a new Anonymous App User ID for the logged out state.

Logging back in

To log in a new user, the provided App User ID should be set again with .logIn().

Switching accounts

If you need to switch from one provided App User ID to another, it's okay to call the .logIn() method directly - you do not need to call logOut() first.

Sharing Subscriptions Across Apps and Platforms

Apps within the same RevenueCat Project share the same App User ID namespace, which means that they also share subscriptions. A user logged in to the same user ID in different apps of the same Project will have access to the same entitlements. This allows sharing of subscription status between different apps, even on different platforms.

Note that anonymous App User IDs are not able to share subscription status across apps and platforms, so you'll need to identify with a custom App User ID via your own authentication system.

📘

Managing Subscriptions

A user can only manage their subscription on the platform it was purchased from.

Tips for Setting App User IDs

ℹī¸ App User IDs Should Not Be Guessable
RevenueCat provides subscription status via the public API, having App User IDs that are easily guessed is not good. It is recommended to use a non-guessable pseudo-random ID.
ℹī¸ Keep App User IDs shorter than 100 characters
App User IDs should not be longer than 100 characters.
⚠ī¸ Don't set emails as App User IDs
For the above reasons about guessability, and GDPR compliance, we don't recommend using email addresses as App User IDs
⚠ī¸ Don't set IDFA as App User IDs
Advertising identifiers should not be used as App User IDs since they can be easily rotated and are not unique across users if limit ad tracking is enabled.
🚨 Don't hardcode strings as App User IDs
You should never hardcode a string as an App User ID, since every install will be treated as the same user in RevenueCat. This will create problems and could unlock entitlements for users that haven't actually purchased.

Every app user ID must be unique per user. If you don't have your own user IDs for some of your users, you should not pass any value for the App User ID on configuration which will rely on the anonymous IDs created by RevenueCat.
🚨 Don't use blocked App User IDs
Certain App User IDs are blocked in RevenueCat. This is by design to help developers that may be unintentionally passing non-unique strings as user identifiers. The current block-list is:
'no_user', 'null', 'none', 'nil', '(null)', '\x00'(NULL character), ''(empty string), 'unidentified', 'undefined', 'unknown', 'anonymous', and 'guest'.

Next Steps