Skip to main content
Solved

Appropriate place to call setEmail in relation to logIn?

  • September 4, 2026
  • 2 replies
  • 56 views

Forum|alt.badge.img

We use the RevenueCat Purchases SDK for Kotlin, version 9.28.1, on our Android app.

In our use case, we want to set or update the user’s e-mail attribute on their RevenueCat profile as part of their logging in to our app. The e-mail is a piece of data that does help during customer support, so we want it to be stored reliably on RevenueCat.

We are aware that user attributes are not immediately synced to the RC backend for calls like setEmail(), and that attribute syncing actually happens implicitly as part of other, more significant, events (or with an explicit syncAttributesAndOfferingsIfNeeded() call.) With this in mind, we do these two calls, one right after the other:

Purchases.sharedInstance.setEmail(...)
Purchases.sharedInstance.logIn(...)

We have browsed the SDK source code and it does look like logIn() is one of the calls for which attribute synchronization happens under the covers on the Kotlin SDK (even though that is not mentioned in the documentation), which might mean that we don’t need an additional explicit call to request syncing. Can you please confirm that is the case?

Now, we are wondering: If a user starts out with an anonymous ID and then logs in (for which we do setEmail() and logIn() as described above), which RevenueCat profile gets updated with the e-mail address? Is it the profile before the logIn(), the one after it, or both? We ask because we see the same e-mail address showing up on both anonymous and identified profiles. So, in practice, it looks like both are updated. As far as what we can gather from the SDK source code, it looks like it’s both, too.

Any input is appreciated.

Best answer by Haley Pace

Hi,  logIn() will sync attributes. On the Android/Kotlin SDK, setEmail() only stores $email locally on the current App User ID. logIn() then syncs unsynced attributes to the backend before it calls identify. You do not need an extra syncAttributesAndOfferingsIfNeeded() if logIn() runs right after setEmail()

Attribute sync on logIn() is not currently listed in the customer attributes docs, I can take note of this behavior there.

With setEmail() then logIn()$email is first saved on the anonymous ID, then identify runs.

If the anonymous ID is aliased/merged with the custom App User ID (the usual first-login case: custom ID is new, or exists but has no anonymous alias yet), they become one customer. Looking up either ID returns the same CustomerInfo and the same attributes — so seeing the email on both is expected, not two separate profiles. If identities are not merged (the custom ID already has an anonymous alias), logIn() switches to that user without transferring data. Email that already synced to the previous anonymous ID stays there.

If you want $email on the logged-in customer even when a merge does not happen, call logIn() first, then setEmail()

2 replies

Forum|alt.badge.img+8
  • RevenueCat Staff
  • Answer
  • September 4, 2026

Hi,  logIn() will sync attributes. On the Android/Kotlin SDK, setEmail() only stores $email locally on the current App User ID. logIn() then syncs unsynced attributes to the backend before it calls identify. You do not need an extra syncAttributesAndOfferingsIfNeeded() if logIn() runs right after setEmail()

Attribute sync on logIn() is not currently listed in the customer attributes docs, I can take note of this behavior there.

With setEmail() then logIn()$email is first saved on the anonymous ID, then identify runs.

If the anonymous ID is aliased/merged with the custom App User ID (the usual first-login case: custom ID is new, or exists but has no anonymous alias yet), they become one customer. Looking up either ID returns the same CustomerInfo and the same attributes — so seeing the email on both is expected, not two separate profiles. If identities are not merged (the custom ID already has an anonymous alias), logIn() switches to that user without transferring data. Email that already synced to the previous anonymous ID stays there.

If you want $email on the logged-in customer even when a merge does not happen, call logIn() first, then setEmail()


Forum|alt.badge.img
  • Author
  • New Member
  • September 7, 2026

@Haley Pace Thank you for your reply.

What we are seeing on the RevenueCat Dashboard when searching for the user’s e-mail address are multiple, separate profiles showing up in the results:

  • Exactly one profile containing the custom ID, which started out with an anonymous ID (a merge happened here.) This one is attached to the entitlement.
  • Multiple ones with a single anonymous ID (no merge) and no entitlement.

That’s why we suspect that calling setEmail() and then logIn() ends up setting both the pre-login profile and the post-login one, particularly when the user reinstalls the app on the same device, or installs it on another device, and then logs in to a profile with a custom ID (linked to Play Store’s purchase receipt.)

If we were to invert the calls (logIn() and then setEmail()), we would think that a  syncAttributesAndOfferingsIfNeeded() call would be needed to ensure the attribute is immediately synced to the RevenueCat backend, right? But then we risk the sync call failing and therefore the email getting lost (unless we make sure to retry the operation, of course.)

What we are looking for is the most reliable way to ensure that the e-mail address is attached to the profile with the custom ID. Please advise.