Identifying Customers
RevenueCat provides a source of truth for a customer's subscription status across different platforms. User identity is one of the most important components of many mobile applications, and it's crucial to make sure the subscription status that RevenueCat is tracking is associated with the correct user.
What is a customer in RevenueCat?
In RevenueCat, the term "customer" refers to the person using an app that utilizes RevenueCat to handle or track the user's purchases. Every customer has a unique CustomerInfo object that can be referenced via their App User ID. As described below, the RevenueCat SDK will automatically generate anonymous App User IDs for customers unless a custom App User ID is provided by the developer. Some apps will use a combination of both custom and anonymous App User IDs, or only one App User ID type.
If you use a combination of anonymous and custom App User IDs, it’s expected that Customers may be merged over time due to various actions they perform within the app, like logins or restores. Scenarios explaining when merges occur are covered in more detail below, and will depend on the restore behavior you select for your project. When a merge of customers occurs, there will be only one App User ID within the original_app_user_id
field. If you’re listening to Webhooks, the other App User IDs associated with the customer will be within an array in the aliases
field. When referenced via the SDK or API, any merged App User IDs will all be treated as the same “customer”. Looking up any of the merged App User IDs in RevenueCat will return the same CustomerInfo
, customer history, customer attributes, subscription status, etc.
Overall, the concept of a customer in RevenueCat is central to the platform's ability to track and manage in-app purchases and subscriptions. By this form of maintaining a detailed record of each customer's activity, developers can gain insights into their app's revenue streams and make informed decisions to optimize their monetization strategies.
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.
- Swift
- Objective-C
- Kotlin
- Java
- Flutter
- React Native
- Cordova
- Capacitor
- Unity
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.configureWith({ apiKey: <public_sdk_key> });
Purchases.configure({ apiKey: <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
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.
- Swift
- Objective-C
- Kotlin
- Java
- Flutter
- React Native
- Cordova
- Capacitor
- Unity
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.configureWith({ apiKey: <public_sdk_key>, appUserID: <my_app_user_id> });
await Purchases.configure({ apiKey: <public_sdk_key>, appUserID: <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.
- Swift
- Objective-C
- Kotlin
- Java
- Flutter
- React Native
- Cordova
- Capacitor
- Unity
// 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) {
// customerInfo 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 { customerInfo, created } = await Purchases.logIn(<my_app_user_id>);
// customerInfo updated for my_app_user_id
// Configure Purchases on app launch
Purchases.configureWith({ apiKey: <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 Purchases on app launch
await Purchases.configure({ apiKey: <public_sdk_key> });
//...
// Later log in providing user Id
try {
const logInResult = await Purchases.logIn({ appUserID: <my_app_user_id>});
} catch (error) {
// Handle error logging in
}
// 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 logging in from an Anonymous ID to a provided custom App User ID, RevenueCat will decide whether the identities should be merged (aliased) into the same CustomerInfo object or not. This is decided depending on whether the provided custom App User ID already exists, and if it does exist whether it has an anonymous alias already.
Current App User ID | Provided Custom App User ID already exists? | Provided Custom App User ID has anonymous alias? | Result |
---|---|---|---|
Anonymous | No | N/A | Anonymous ID and Provided ID have CustomerInfo merged. |
Anonymous | Yes | No | Anonymous ID and Provided ID have CustomerInfo merged. |
Anonymous | Yes | Yes | CustomerInfo transfers to Provided ID, no aliases created. |
Non-anonymous | Any | Any | CustomerInfo transfers to Provided ID, no aliases created. |
Logging Out
When an identified user logs out of your application you should call the logOut()
method within the SDK. This will generate a new anonymous App User ID for the logged out state. However, if you plan to use only custom App User ID's, you can follow the instructions here.
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.