Accounts, Login, and Logout

If you create user accounts for your app users, we describe in this guide how to integrate this information with Nami.

If your app allows users to create accounts or you have accounts that a user can create to share access to your platform across multiple platforms like the Apple, Android, and the Web, Nami provides some methods to link that account to the Nami concept of a user.

There are 2 important concepts related to supporting accounts in your app.

  1. A known unique identifier for the account
  2. Access to any entitlements granted via a purchase of your products

Uniquely identifying accounts

Nami provides a simple call to send us a unique identifier that defines a known user with an account. An example call to set a UUID as a unique identifier looks like:

Nami.setExternalIdentifier(externalIdentifier: "035b30e2-faf4-462d-aec3-caa0fbe26c49", type: .uuid)
[Nami setExternalIdentifierWithExternalIdentifier:@"035b30e2-faf4-462d-aec3-caa0fbe26c49" type:NamiExternalIdentifierTypeUuid]
Nami.setExternalIdentifier("035b30e2-faf4-462d-aec3-caa0fbe26c49", NamiExternalIdentifierType.UUID)
Nami.setExternalIdentifier("035b30e2-faf4-462d-aec3-caa0fbe26c49", NamiExternalIdentifierType.UUID)
NativeModules.NamiBridge.setExternalIdentifier("035b30e2-faf4-462d-aec3-caa0fbe26c49", "uuid");
Nami.setExternalIdentifier("035b30e2-faf4-462d-aec3-caa0fbe26c49", NamiExternalIdentifierType.uuid);

There are two important things to know about external identifiers.

Nami only accepts two types for external identifiers:

  • SHA256
  • UUID

If you wish to use a piece of data on your side that is more descriptive, such as an email address or a username, we recommend computing the SHA256 for that descriptor and using the result when your call our SDK.

At this time Nami can only store a single external identifier for a customer. If you make a subsequent call to setExternalIdentifier with a new value, we will transfer the user on our side to a new user that is defined by the new external identifier.

If a user signs out or switches accounts, you can clear a previously set identifier with the following call:

Nami.clearExternalIdentifier()
[Nami clearExternalIdentifier];
Nami.clearExternalIdentifier()
Nami.clearExternalIdentifier();
NativeModules.NamiBridge.clearExternalIdentifier();
Nami.clearExternalIdentifier();

Sharing entitlements cross-platform

If the Nami SDKs are installed on all your platforms where you sell access to your product, then correct access to entitlements can be entirely handled via the External Identifiers described in the previous section.

Simply make sure that the same External Identifier is set for the account on all devices and then any purchase that grants an entitlement will correctly share it with all other devices that are linked to that account.

If you sell on additional platforms where Nami either does not have an SDK or you have not integrated the Nami SDK yet, there is one additional step to take to ensure your users are properly granted access to any entitlement they have purchased.

This can be done with the setEntitlements method. The only required parameter you must set when making this call is the Entitlement Reference ID that you have defined in the Control Center.

To find this ID, simply login in to the Control Center, go to the Entitlements section and find the ID under the ID column or directly under the name on mobile.

1211 616

👍

Nami Best Practice

Only use setEntitlements to grant access to a purchase made on a platform you do not have Nami integrated with. It is better to rely on Nami to manage entitlements created by on-platform purchases to ensure they expire and renew at the correct times, including in more complex situations like grace period and account holds.

To set an entitlement that is not managed by Nami, simple call the method:

let setter = NamiEntitlementSetter(id: "premium_access")
NamiEntitlementManager.setEntitlements([setter])
NamiEntitlementSetter *setter = [[NamiEntitlementSetter alloc] initWithId:@"premium_access"];
[NamiEntitlementManager setEntitlements:@[setter]];
val setter = NamiEntitlementSetter(referenceId = "premium_access")
NamiEntitlementManager.setEntitlements(listOf(setter))
NamiEntitlementSetter setter = new NamiEntitlementSetter("premium_access");
NamiEntitlementManager.setEntitlements(Collections.singletonList(setter));
var setter = NamiEntitlementSetter(referenceId: "premium_access");
NamiEntitlementManager.setEntitlements([setter]);

Note that setEntitlements may be used to grant multiple entitlements to a user at the same time if your app has more than one entitlement.

👍

Nami Best Practice

We strongly recommend that when manually setting entitlements with the setEntitlements method that you provide an expiration date and the platform where the purchase was made, if these data are available.

This will help Nami do a better job of ensuring that the entitlement is not granted forever for a user.

The NamiEntitlementSetter object also optionally takes a parameter purchasedSKUid. If this is available and you sell different SKUs for the same entitlement this information can be informative to the platform and analytics about and we encourage you to include it.

Example of how to set additional parameters for the entitlement:

let expirationDate = "2020-09-01T12:00:00+0000"

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"

let expires = dateFormatter.date(from:expirationDate)!

let setter = NamiEntitlementSetter(
  id: "premium_access",
  platform: .web,
  purchasedSKUid: "monthly_subscription",
  expires: expires
)
NamiEntitlementManager.setEntitlements([setter])
NSString *expirationDate = @"2020-09-01T12:00:00+0000";

NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
    
NSDate *expires = [dateFormatter dateFromString:expirationDate];
   
NamiEntitlementSetter *setter = [[NamiEntitlementSetter alloc] initWithId:@"premium_access" platform:NamiPlatformTypeWeb purchasedSKUid:@"monthly_subscription" expires:expires];
[NamiEntitlementManager setEntitlements:@[setter]];
val expires = Calendar.getInstance().let { calendar ->
    calendar.set(2020, Calendar.SEPTEMBER, 1, 12, 0)
    calendar.time
}
val setter = NamiEntitlementSetter(
    referenceId = "premium_access",
    platform = NamiPlatformType.WEB,
    purchasedSKUid = "monthly_subscription",
    expires = expires
)
NamiEntitlementManager.setEntitlements(listOf(setter))
Calendar calendar = Calendar.getInstance();
calendar.set(2020, Calendar.SEPTEMBER, 1, 12, 0);
Date expires = calendar.getTime();
NamiEntitlementSetter setter = new NamiEntitlementSetter("premium_access", NamiPlatformType.WEB, "monthly_subscription", expires);
NamiEntitlementManager.setEntitlements(Collections.singletonList(setter));
var expires = DateTime(2020, 9, 1, 12, 0);
var setter = NamiEntitlementSetter("premium_access", NamiPlatformType.web,
        "monthly_subscription", expires);
NamiEntitlementManager.setEntitlements([setter]);

You may remove an entitlement from a user that was set with setEntitlements by calling clearAllEntitlements.

NamiEntitlementManager.clearAllEntitlements()
[NamiEntitlementManager clearAllEntitlements];
NamiEntitlementManager.clearAllEntitlements()
NamiEntitlementManager.clearAllEntitlements();
NativeModules.NamiEntitlementManagerBridge.clearAllEntitlements()
NamiEntitlementManager.clearAllEntitlements();

📘

clearAllEntitlements only removes entitlements set via a previous call to setEntitlements. For platforms that you have integrated with Nami, our platform will manage those entitlements based on signals we receive from the stores and our SDKs.

Best practices for implementation

We recommend adding the code described above to your app where the following scenarios occur.

ScenarioNami SDK Calls
Account creation1. Call setExternalIdentifier
Login1. Call setExternalIdentifier
2. Check if there are any entitlements for a platform not managed by Nami
2a. If yes call setEntitlements
Sign out1. Call clearExternalIdentifier
First session after an app kill1. Call setExternalIdentfier
2. Call setEntitlements with the list of all current active entitlements not created by on-platform purchases.

📘

In the sign out scenario, calling clearExternalIdentifier will also remove any entitlements from the device. It is not necessary to call clearAllEntitlements. Any previously set entitlements will remain with the user account defined by the external identifier and will be able to be accessed again on a subsequent sign-in.

📘

Why send data after an app kill?

This is a best practice to ensure that the state of the Nami platform is correct without having to make too many network calls to the Nami servers.

Resending these data on the next session after an app kill helps ensure that your user account and entitlement state are properly synced with the Nami platform.

Linking data from Nami ML to your systems

Nami produces a number of events to help manage both the state of your users and how they progress through the lifecycle of your subscription products which we can send to you via Enabling Webhooks or through one of our partners, like mParticle.

If you have provided us with an external identifier, it will be attached to all user.subscription.* and user.journey.* events we produce.

Read more about our events here.

Combating fraud and account sharing

Nami has built-in some protections to ensure that a user cannot simply sign-in to multiple accounts to share a single purchase with multiple different accounts.

On our platform, we create a single user or account object that is linked to the External Identifier that you set as described above.

An entitlement on our platform is always linked to a single user or customer account. If the user signs in with a different account and they have an active purchase, that entitlement will transfer from the old account to the new account.

The Nami platform is designed to ensure that a purchase made on-device will always activate the entitlement for the user and account currently tied to that device. In a case where that on-device purchase is transferred to a new user account, any other devices that are linked to the old user account will lose access to the entitlement.

We produce user.subscription.transferred.from and user.subscription.transferred.to events when this situation occurs so you can gain insight into when this happens, which you can receive via Webhook or mParticle as described above.