Time-Limited in-App Purchase

I want to let some non-consumable iAP items just be sold during a particular period of time. Also the user who purchased these items still can restore and use it after the time period has elapsed.

Creating time-based in-app purchases (iAP) can be difficult. First all iAPs would need to go through App Review, hence they would need to be available before your app is live. Second is that there’s practically no way for the app to differentiate the app review environment versus the actual production environment – nor does Apple want you to.

But what if I say it can be done? What if you can have a non-consumable iAP, pass it through app review, and only made it for sale only during a specific period in the future? Interested? read on.

Suppose that you have an iAP for a year-end holiday special that is only for sale in the second half of December. In the following January, the item won’t be available any more. However users who purchased it during its two-week availability can use it indefinitely including restoring their purchase of the item in future devices. It is now August and you are preparing your app’s update which will contain the code and assets for that iAP.

The key is to have the iAP visible (thus can be purchased by the user) only during the “holiday special” period, but remains hidden at any other time. The catch is that Apple’s app reviewers would need to see your iAP or otherwise won’t approve it.

In app purchase holiday sale

Option One

Now for this technique to work, you would need to have a backend for the app. A server that the app can contact during its entire lifecycle. Because you’re going to use this server to put additional logic over your iAP code.

Having a server ready, you would need to modify your app’s built-in iAP store. The business logic would check two places for iAP products, Apple’s server and your server. When displaying the list of iAP products, the app would follow a flow like this:

  1. Ask Apple’s App Store for available iAP product descriptions and their prices using SKProductsRequest.
  2. Split the returned product list into two groups, the ones that the user had purchased versus the ones that are still available for purchase (or consumable products).
  3. For products that the user have purchased, show them immediately with status as “purchased” (for non-consumables) or the amount that the user has on-hand (for consumables). Showing the status gives confidence to the user that his/her purchase is “still there”.
  4. For the products that the user haven’t purchased (or depleted consumables), ask your server whether it is okay to display them. This allows you to control the iAP’s availability to the user beyond its status in the App Store.

In short, products that are not available for purchase are hidden by your app. Which in turn, is controlled by a server-side switch.

Then the workflow to update the app’s binary in the app store would likely be similar to the following:

  1. You manually enable the iAP from your server.
  2. You submit the app for review to the App Store. However when submitting, you select the Manually release this version under the Version Release heading. Thus after the app is approved, you would need to release it manually.
  3. When the app has passed review, you configure the server to hide the iAP and schedule it to be available only in the second half of December.
  4. Go to App Store Connect and release the app. At this point of time, the iAP status is Cleared for Sale but won’t be shown by the app since the server say to hide it.

Option Two

What if you can’t have any backend for the app? It would require more manual work and careful timing, but it is possible.

Still going by the year-end special iAP example. You would need to manually toggle the Cleared for Sale checkbox in App Store Connect as according to the iAP’s availability. Thus just before the second week of December, you would need to login to App Store Connect and tick a checkbox. Likewise in early January you would need to clear that same checkbox. In turn this would render the product to be “valid” or “invalid” from the app’s point of view.

Therefore the app would need to completely rely on Apple’s server to tell its availability. It would need to prepare for invalid product values returned from the product request call and act accordingly. The flow of displaying iAP in the app would look something like this:

  1. Ask Apple’s App Store for available iAP product descriptions and their prices using SKProductsRequest. (Same as before).
  2. Split the returned product list into three groups:
    • Purchased.
    • Still available for purchase, or consumable products.
    • Invalid product identifiers. These would be listed in invalidProductIdentifiers of SKProductsResponse.
  3. For products that the user have purchased, show them immediately with status as “purchased” (for non-consumables) or the amount that the user has on-hand (for consumables). Showing the status gives confidence to the user that his/her purchase is “still there”. (No difference here).
  4. For products identifiers that are listed in invalidProductIdentifiers, do not show them. Even if you found those products in the products array of SKProductsResponse.
  5. For products that are still available, show them as per normal.

Accordingly, the flow to submit the app’s update is a bit different.

  1. Create the iAP with the Cleared for Sale option enabled. This is so that App Review can see it in your app and approve the iAP.
  2. When submitting the app, also select Manually release this version so that you are able to make some changes before the app goes live.
  3. After the app is approved, but before you release the app, uncheck the iAP’s Cleared for Sale option so that it is not available to users.
  4. Finally release the app.

Now since you don’t have any backend server, you would need to wait until one day before the iAP becomes available for users to purchase and then tick its Cleared for Sale checkbox in App Store connect. Remember there are time zone differences, so that your December 15 may be someone else’s December 14. Finally one day after the iAP shouldn’t be available any more, clear the Cleared for Sale checkbox. Refer to Set availability for in-app purchases for more information.

Next Steps

Go ahead and try out this workflow before you really need it. Say that you’re launching a new iAP. Don’t make it available immediately when the app update is live. Instead introduce an artificial delay (say for example one week) in which the iAP would be available after the update. Double check it with the live instance of your app (not just the development or TestFlight builds). That way you’ll be confident that this method would be in your toolset when you do need a “holiday special” item.

Avoid App Review rules by distributing outside the Mac App Store!

Get my FREE cheat sheets to help you distribute real macOS applications directly to power users.

* indicates required

When you subscribe you’ll also get programming tips, business advices, and career rants from the trenches about twice a month. I respect your e-mail privacy.

One thought on “Time-Limited in-App Purchase

  1. Good post, thanks.

    Whilst option #2 would work, there really is no good reason to go completely serverless for this. It is not like the app can be completely offline anyway, because it is needing to contact Apple’s servers and make the purchase.

    Just use a free GitHub account, and store a JSON config file in a publicly readable repository. Check this file in order to see which IAPs you should request using the SKProductsRequest. This method takes minutes to setup, costs nothing, and requires no additional SDKs etc.