Non-consumable IAP for free trial

Hello. My newly released app includes a 1 day free trial. I've done this by creating a non-consumable in-app purchase priced at 0. I consider the free trial active if there's a transaction (from Transaction.currentEntitlements) for that product such that transaction.originalPurchaseDate is less than 24 hours ago. This works fine locally in the simulator and also in TestFlight, however it does not seem to work in the actual app from the App Store. The user can "purchase" it fine; they see the purchase sheet with the product name and the $0.00 price, and when they double press the side button it all seems to work. However, the app then behaves as if it didn't work. The free trial product is no longer available though.

One thing is that I didn't follow the naming convention “XX-day Trial”. Could that be the problem? If so, is that meant to be for the product reference name?

Is the issue that there is no transaction for this product in the entitlements, or is the issue that the originalPurchaseDate is not what you expect?

To understand this, you need to get telemetry from your app (by either writing to a log and asking the user to export and send bit to you or by sending events to a server)

I would recommend sending the current date, originalPurchaseDate and just in case also the purchaseDate (to see if there is any difference).

However, my first suspect would be the time difference calculation. Maybe you took into account timezone differences where it is not required? The user who had an issue might be on a different time zone. Ask someone to review the code.

Regarding your overall strategy, you should consider two things (which might not be real issues, depending on the popularity of your app and the motivation to "hack" it):

  • Using the system time (eg Date.now) allows users to change the devices clock to a previous date. If they do it each time before launching your app they could get a "free trial" indefinitely.

  • I believe originalPurchaseDate and purchaseDate do not take refunds into account. So a user might request a refund and re-purchase the IAP. This new transaction will have a later originalPurchaseDate and the old one will not appear in currentEntitlements anymore.

Thanks for the reply and insights.

I don't think it's a time zone issue. I have another paid consumable "1 day pass" IAP with the exact same timing logic and it works just fine. I'm using relative date/time methods -- i.e. originalPurchaseDate.addingTimeInterval(...) and expiryDate.timeIntervalSinceNow.

From the app logic I can definitely determine that there is a verified transaction for the free non-consumable, but yeah originalPurchaseDate not what I expect.

I'll need to figure out how to add some logging that I can retrieve somehow!

Non-consumable IAP for free trial
 
 
Q