Skip to main content
Question

Handling subscribed users who complain they do not have access to their benefits.


We get a fair number customer support messages that state something along the lines of “The app forgot that I have premium access and I had to click restore purchases.” We store subscription status to a persistent state in redux so it is confusing to us where they may be losing access to their subscriber benefits. Have other apps dealt with this? Are there common race conditions on startup that can lead to this. 

Anecdotally it seems to happen a lot with family sharing. Sometimes it’s user error (user signs in once, and then accidentally creates a new anonymous account). Looking for common patterns we may be handling incorrectly.

Is it common for apps to get customer support requests like these?

3 replies

Userlevel 2
Badge +4

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!

Userlevel 2
Badge +7

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.active[revenueCatOffering] !==
'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()[Slices.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]);

 

Userlevel 5
Badge +9

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.

Reply