Question

Automatic Renewal event after App-Reinstall has only anonymous app user id

  • 5 November 2021
  • 5 replies
  • 162 views

Badge +3

Hi, really loving RevenueCat!

I have the following situation:

  • Android App
  • I initialize Purchases SDK in the AndroidApplication class with an anonymous User ID
  • User logs in → I log in the user into the purchases SDK
  • → User has an anonymous ID + my domain user ID

The problem happens, when the following happens:

  • The user purchases a subscription with automatic renewal
  • The user uninstalls the app and then installs it again
  • The next time the webhook calls my backend for the renewal, it will contain ONLY an previously unknown anonymous ID and no way for me to match it to the user

The main problem stems from this I believe:

Current App User ID Provided App User ID already exists? Provided App User ID has anonymous alias? Result
Anonymous Yes Yes PurchaserInfo changes to Provided ID, no aliases created.

 

My solution is to manually alias the current app user Id every time a user logs in IF the current app user id is an anonymous one. It has worked so far, however, it feels strange.

 

Is this the correct approach?

 

Additionally, could someone explain to me, why in this case, the approach is to not alias the user IDs for me to better understand what I could break by doing this?


5 replies

Badge +3

Of course. However, I still don’t know if this has any negative side effects, so use with care. I would also appreciate any insights you might gain!

One side-effect is, that every time a user logs out/back in there will be an alias created.

 

suspend fun signIn(
userId: String,
email: String?,
displayName: String?
): Pair<BillingUser, Boolean> {
val previousUserId = purchases.appUserID
val user = signIntoRevenueCat(userId, email, displayName)
if (previousUserId.isAnonymous())
createRevenueCatAlias(previousUserId)
return user
}

private suspend fun signIntoRevenueCat(
userId: String,
email: String?,
displayName: String?
): Pair<BillingUser, Boolean> {
return suspendCoroutine { cont ->
purchases.logInWith(
appUserID = userId,
onError = { cont.failure(it) },
onSuccess = { purchaser, created ->
purchases.setEmail(email)
purchases.setDisplayName(displayName)
cont.resume(purchaser to created)
},
)
}
}

private suspend fun createRevenueCatAlias(userId: String) {
return suspendCoroutine { cont ->
purchases.createAliasWith(
newAppUserID = userId,
onError = { cont.failure(it) },
onSuccess = { cont.resume(Unit) }
)
}
}

@RevenueCat you should really add Kotlin Syntax highlighting ;)

Badge +1

Thank you so much @Jimi Steidl 

I am currently using flutter_purchases v 3.9.4 and createAlias is deprecated.

The only thing I can do with the methods provided is “login”.

  @override
Future purchaseLogIn(String uid) async {
try {
await Purchases.logIn(uid);
} on PlatformException catch (_) {
throw Failure(message: 'Failed to login.');
}
}

I’ll let you know if I choose to downgrade my version and try your solution (with createAlias).

 

@sharif I have an issue with RevenueCat using flutter_purchases v 3.9.4.

The problem is similar to the one described by @Jimi Steidl: after purchasing a subscription, deinstalling my application, installing it again and checking my current product, I cannot get my current subscription in my app. Instead, it says I am on the free plan while I am on a paid plan. The await Purchases.getPurchaserInfo() method does not find any active entitlement, while it is.

At the moment of the purchase, I can clearly see in the RevenueCat dashboard, a purchase was carried out with my Firebase user UID. Indeed when I login to my application, I first do a “regular login”, where I authenticate to my backend, and right after, I use my app user to login to RevenueCat.

Is there anything wrong with this approach?

Any idea why this issue happens?

 

Thank you

Userlevel 5
Badge +9

Are you calling login before any calls to purchasePackage/purchaseProduct or restoreTransactions/syncPurchases? Calling login before calling those methods will make sure the correct app user ID is used for purchases. Otherwise, what might be happening is the purchase is being attached to the anonymous ID before the SDK can identify them. If this is happening to your users, you may be able to reproduce the behavior in testing and figure out what code path is causing this. Just turn on debug logging when testing to get a full view of what app user ID is being used throughout the run. Try common actions like making a purchase then uninstalling/reinstalling the app and logging out and in that might cause this behavior.

Badge +3

I can easily reproduce the behaviour, I have described the steps above, but in terms of sdk calls:

  • loginWith(myDomainUserId)
  • purchasePackageWith(...)
  • -- Now my user uninstalls/reinstalls
  • loginWith(myDomainUserId) ← Same user ID as before
  • -- The purchases are recognized correctly inside the app
  • -- The webhook calls my server for an automatic renewal with a previously unknown anonymous ID

I have fixed this behavior by manually aliasing any anonymous ID with the current user after every login.

  • loginWith(myDomainUserId)
  • if (previousId.isAnonymous()) createAlias(previousId)
Badge +1

Hey @Jimi Steidl 

I have the same issue as yours.

Would you mind sharing the code where you manually alias any anonymous ID with the current user after every login?

Thank you

Loic

Reply