@trabdin great, glad it worked!
This is what I have. I have people upgraded and using it, haven’t heard any issues -- I think it all worked seamlessly.
I have a customer info update listener -- maybe you need this?
await Purchases.setLogLevel({ level: LOG_LEVEL.DEBUG }); // Enable to get debug logs
await Purchases.configure({
apiKey: this.getRevenueCatKey(),
});
const hasSynced = await this.storage.getPref('RC_PURCHASES_SYNCED');
if (!hasSynced) {
await Purchases.syncPurchases();
await this.storage.setPref('RC_PURCHASES_SYNCED', 'true');
console.log('RevenueCat purchases synced');
}
await this.getRcOfferings();
const ci = await Purchases.getCustomerInfo();
this.handleRcPermissions(ci.customerInfo);
await Purchases.addCustomerInfoUpdateListener((customerInfo) => {
// console.log('customerInfoUpdateListener', customerInfo);
this.handleRcPermissions(customerInfo);
});
Thanks, that did it. I thought CustomerInfo would already be updated if waiting for the syncPurchases function to resolve, but it looks like it takes a little time after syncPurchases for CustomerInfo to be updated.
This is what I have. I have people upgraded and using it, haven’t heard any issues -- I think it all worked seamlessly.
I have a customer info update listener -- maybe you need this?
await Purchases.setLogLevel({ level: LOG_LEVEL.DEBUG }); // Enable to get debug logs
await Purchases.configure({
apiKey: this.getRevenueCatKey(),
});
const hasSynced = await this.storage.getPref('RC_PURCHASES_SYNCED');
if (!hasSynced) {
await Purchases.syncPurchases();
await this.storage.setPref('RC_PURCHASES_SYNCED', 'true');
console.log('RevenueCat purchases synced');
}
await this.getRcOfferings();
const ci = await Purchases.getCustomerInfo();
this.handleRcPermissions(ci.customerInfo);
await Purchases.addCustomerInfoUpdateListener((customerInfo) => {
// console.log('customerInfoUpdateListener', customerInfo);
this.handleRcPermissions(customerInfo);
});
Thanks for the answers, I just tried syncPurchases (with the capacitor library)..
So I first call configure(), then syncPurchases() if I haven’t already done it in a previous app init, and then getCustomerInfo() to check if the user has an active subscription for a specific entitlement.
But I noticed that when I call syncPurchases() and then getCustomerInfo(), it doesn’t return that the entitlement is active, but it does so the next time I open the app and getCustomerInfo() is called..
Is it possible for the getCustomerInfo() to return that the entitlement is active directly after running syncPurchases()? Or do I need to do something else in between? I noticed that syncPurchases() should return a CustomerInfo object but it doesn’t for the capacitor library?
> I’m not sure what the best practice is here to be honest, or whether I was never supposed to have both anonymous and custom IDs at the same time.
You can create an anonymous ID for those users and import them. When those users open their app, they could restore purchases which should merge both accounts
Hi, what would be the difference between importing from Glassfy and then the user still needing to restore purchases, and the user just restoring their purchases?
I also need to migrate from Glassfy to RevenueCat and also got an export from Glassfy without any user id:s.. wondering if I should use that or syncPurchases..
What would be the best way to only run syncPurchases once? Saving the syncPurchases run in local storage? But then it would be run again if the user re-installs the app (or maybe that wouldn’t be a big issue?)..
Thanks!
I don’t have real answers as I’m navigating this as well.
I load a didSyncPurchases flag from my storage, defaults to false. If they did not sync yet, I call syncPurchases once per user in the app and then save the didSyncPurchases to storage locally so the next time it doesn’t sync again.
> Hi, what would be the difference between importing from Glassfy and then the user still needing to restore purchases, and the user just restoring their purchases?
The only difference is that if that user never opens the app, you won’t have that data and that the user would need to restore (unless you force a sync purchase)
>What would be the best way to only run syncPurchases once? Saving the syncPurchases run in local storage? But then it would be run again if the user re-installs the app (or maybe that wouldn’t be a big issue?)..
As long as you don’t call it on every launch, it should be fine. You can also force a sync only if the user does not have a purchases
> I’m not sure what the best practice is here to be honest, or whether I was never supposed to have both anonymous and custom IDs at the same time.
You can create an anonymous ID for those users and import them. When those users open their app, they could restore purchases which should merge both accounts
Hi, what would be the difference between importing from Glassfy and then the user still needing to restore purchases, and the user just restoring their purchases?
I also need to migrate from Glassfy to RevenueCat and also got an export from Glassfy without any user id:s.. wondering if I should use that or syncPurchases..
What would be the best way to only run syncPurchases once? Saving the syncPurchases run in local storage? But then it would be run again if the user re-installs the app (or maybe that wouldn’t be a big issue?)..
Thanks!
>if you’re still offering a look-over, I’d love to take you up on it. How do I get you my account details?
I’ve checked your app and at a first glance, all looks good. I see both android and apple apps configured, both with notifications configured and we are getting them and I can see production purchases.
> I’m not sure what the best practice is here to be honest, or whether I was never supposed to have both anonymous and custom IDs at the same time.
You can create an anonymous ID for those users and import them. When those users open their app, they could restore purchases which should merge both accounts
If you want anything in particular you want me to review, send me a DM
I have the same issue with the Glassfy export csv file.
The app_user_id (e.g. “Subscriber ID”) field is empty.
I’m not sure how to handle the import in Revenuecat.
@snapdown you rock -- thank you for sharing.
The export I got from Glassfy had slightly different columns, so it required a few edits, but the script worked well!
What sucks has nothing to do w/ the script, but the export Glassfy gave me -- I have custom user ids as well as anonymous users for when they purchase without login, and Glassfy unfortunately did not export the anonymous app_user_ids (the “Subscriber ID” they use in their system) and left them as blank.
Which meant a lot of data was skipped on import because blank ids are understandably not allowed.
I’m not sure what the best practice is here to be honest, or whether I was never supposed to have both anonymous and custom IDs at the same time.
@MarcosC if you’re still offering a look-over, I’d love to take you up on it. How do I get you my account details?
if you have a lot of receipts, definitely see if they will import. It took hours and hours to do 12,000 receipts here, it seemed to rate limit to about 2 seconds per receipt. I had a network failure at some point about 4,500 in. I then amended my import script to take a --start-index param to resume.
This version has --start-index as an optional param: https://gist.github.com/foerster/9b2b93b571791d9293c78747f1c2cee7
Though things feel a bit disjointed and like you have to jump all around, and the code samples are really lacking in how to actually interpret the data, I managed to get both my apps converted over.
@MarcosC if you’re still offering a look-over, I’d love to take you up on it. How do I get you my account details?
For anyone who needs to import, here’s a gist of the script. Usage instructions are in the script also.
https://gist.github.com/foerster/9b2b93b571791d9293c78747f1c2cee7
@snapdown yes, please send it. andre@spicyapps.com
@andrefromspicyapps the script is written in python. If you want it, I can send. You just need to run it with your api key and the csv file from glassfy, it’ll then import all the data for you. You run it once for ios and once for android.
@snapdown thanks for reply. What language is your script made in.
For a smooth and easy migration I didn’t expect to write my own scripts.
I have received a csv export 280 MB big from Glassfy, but I don’t know how to handle this file.
Can I upload it somewhere at revenue cat ?
You need to write a script to import them to revenucat. I don’t know why they don’t show an example, but I have one I wrote I can send to you. It should work with android and ios imports from glassfy.
I have received a csv export 280 MB big from Glassfy, but I don’t know how to handle this file.
Can I upload it somewhere at revenue cat ?
@potatocat666 what language are you using? My assumption is that you are using a hybrid SDK (not native).
Apple and Google are slightly different. In iOS you need to call `checkTrialOrIntroductoryPriceEligibility` because we have to check at runtime if you are elegible and sign the offer. In Google in most cases, Google is the one to determine if you are elegible or not. (except for dev determined offers).
You’ll need to check trial eligibility based on the platform:
- On Apple, you would use `checkTrialOrIntroductoryPriceEligibility`
@MarcosC I think that last issue w/ custom subscribers was a me problem due to having too many test accounts. Sorry!
One loose end - Google Play Trials
I have free trials setup on both google play and iOS, but it appears “checkTrialOrIntroductoryPriceEligibility” is only available for iOS, and trials are applied automatically for Google Play users. But I show different content to the user based on if they’re eligible for the trial or not.
How should I handle that use case inside RevenueCat? I admit I’m still doing paywalls DIY style in the app.
@MarcosC Thank you. On my one app where android wasn’t working -- I think the folks who subscribed (it was a small number) just aren’t able to access the app because glassfy didn’t know about them. I asked for help and they just said ‘you must not have set it up correctly’. That was helpful ::eyeroll::.
If you are able to help see where I went wrong in the play/google setup, that’d be great as I’d love to get them working in RC. I’m sure there’ something small I missed, but I went through several times and couldn’t find it.
>I will figure out how to import these.
To import them, just write a simple script that goes line by line of the CSV file and calls this endpoint → https://www.revenuecat.com/docs/api-v1#tag/transactions/operation/receipts
> Also, for my one app, android wasn’t set up correctly, glassfy would never help me resolve it, so none of the android subscribers are synced to glassfy on that one.
Do you need any help with this? Were you using WatcherMode on this app?
> So do I need to do anything special, or just let RC assign an ID?
Perfect, the same here. You can use our anonymous IDs.
If you want to review anything together, just let me know, happy to help
@MarcosC : Glassfy just sent me two CSVs of receipts, one for android and one for apple. I may not get app versions out super quickly, but I don’t have much subscriber activity right now as it’s offseason for my app (it’s very seasonal).
I will figure out how to import these.
After I do, do I need to do anything special in the apps? I figure I should still call syncPurchases just to make sure we got them all (I know my android users had some hiccups in glassfy for one of my apps).
Also, for my one app, android wasn’t set up correctly, glassfy would never help me resolve it, so none of the android subscribers are synced to glassfy on that one.
I did not do any special user IDs in glassfy -- just whatever they assigned. So do I need to do anything special, or just let RC assign an ID?