Hi @jake lynch! This tends to happen most often in the situation you described, where users inadvertently create new anonymous accounts. Other than that, however, I’d be happy to dig in to how you’re checking for subscription status. Are you fetching customerInfo at various times in your app’s lifecycle? How does your redux store work? If you can share some code, that might help us get to the bottom of this.
Thanks!
We have a slice, which we call PaywallSlice, that we persist using redux-persist. In it there is a property `isSubscribed` which is a boolean that describes whether or not a user is subscribed.
We then have an async thunk that we use to check if the user is subscribed in RC:
/**
* Fetch if the current user is subscribed in RevenueCat
*/
export const fetchRevenueCatSubscriptionThunk = createAsyncThunk<
{
isUserSubscribed: boolean;
latestExpirationDate: string | null;
},
{
uid: string;
revenueCatOffering: string;
}
>(
`${Slices.Paywall}/fetchRevenueCatSubscriptionThunk`,
async ({ uid, revenueCatOffering }, { dispatch }) => {
try {
// Login the current users to RevenueCat
const customerInfo = await Purchases.getCustomerInfo();
const revenueCatIsUserSubscribed =
typeof customerInfo.entitlements.activeirevenueCatOffering] !==
'undefined';
const latestExpirationDate = customerInfo.latestExpirationDate;
/**
* Override subscription if `DEV_IS_SUBSCRIBED` is "true"
*/
const isUserSubscribed =
revenueCatIsUserSubscribed
return {
isUserSubscribed,
latestExpirationDate,
};
} catch (err) {
logError(err);
throw err;
}
},
);
we then have a context which we dispatch the thunk
const setupPurchases = useCallback(
async (uid: string) => {
const { isSubscribed } = store.getState()eSlices.Paywall];
const isConfigured = await Purchases.isConfigured();
/**
* If the Purchases SDK is not configured, then call configure and
* then grab is the user is subscribed
*/
if (!isConfigured) {
/**
* Per docs, this is recommended to be called when the app has access
* to the uid
*
* @see: https://www.revenuecat.com/docs/restoring-purchases#google-play-on-android
*/
await initRevenueCat(uid);
} else {
await Purchases.logIn(uid);
}
// iOS only Superwall setup
if (IS_IOS) {
if (!superwallService.isInitialized) {
await superwallService.initialize(isSubscribed);
}
superwallService.identify(uid);
} else {
// Let Superwall service know it wont be used
superwallService.disable();
}
setHasInitializedPurchases(true);
dispatch(
fetchRevenueCatSubscriptionThunk({
uid,
revenueCatOffering: REVENUECAT_ENTITLEMENT_ID,
}),
);
// Do some other stuff
},
user?.metadata.creationTime, user?.email, dispatch, store],
);
useEffect(() => {
if (user?.uid) {
setupPurchases(user.uid);
}
}, }setupPurchases, user?.uid]);
Hey @jake lynch,
Sorry for the delay! The code doesn’t look obviously buggy to me, and it sounds this is not a widespread occurrence but rather affects a portion of your users so it doesn’t sound to me like there’s a basic or fundamental flaw in your code. At most you might have an edge case or race condition that these users run into. But I will say that it’s quite common for users to have trouble with family sharing as it’s a buggy feature in iOS and Android, and account confusion happens all the time. Our number one recommendation is to have a restore purchases button in your app to resolve exactly this issues. One thing you can do is store a persistent value on the device that can tip you off on account confusion issues. When a user logs in, save their user ID to a place that won’t get wiped when the app is deleted - for example in iCloud or Google Drive. Then on a fresh install, check for that value. If it exists, it means that this is likely a returning user. You have options for how to handle it - you can automatically log the user in, let them know that there’s a user ID cached on the device, restore purchases automatically, etc. I don’t think you’ll ever completely eliminate these kinds of customer support queries just due to the nature of how applications and in-app purchases work, but you might be able to cut down on them using that technique.