We spent over 5 years building a completely free iOS app, only to start charging for it now. We learned a lot throughout this process, and hopefully you can learn a little something from our experience.
With such a variety of documentation out there, you’re almost guaranteed to get lost. Here’s where to actually start: https://developer.apple.com/in-app-purchase/
Complexity 1 – Plan for a phased release schedule
We’ve been free to use for many years, what’s the harm in waiting just a little more? For existing users, our product team wanted to give a little more than Apple’s free-trial introductory offer, so we built a soft-paywall in-app that allows users to subscribe at a discounted price or continue to use the app for free for a little longer and subscribe later. In case they miss this, we’ll also send them an email allowing them to subscribe from the web at the same discounted rate. Having this soft-paywall instead of a hard-paywall saved our butts, I’ll explain later! So our release schedule looks something like this:
T-0: Release the new version of Boomerang to the App Store. Expected app behaviors:
App Version | New Users | Existing Free Users | Existing Subscribers |
---|---|---|---|
Users on old app | No change (free to use) | Receive web discount email, still free to use | No change |
Users on updated app | Subscription required (with free-trial) | Show discounted subscription offer or continue to use for free. | Thank you for being an existing subscriber! |
T+14 Days: Start the paywall for existing users. Expected app behaviors:
App Version | New Users | Existing Free Users | Existing Subscribers |
---|---|---|---|
Users on old app | No change (free to use) | No change (free to use) | No change |
Users on updated app | Subscription required (with free-trial) | Subscription required (with free-trial) | Thank you for being an existing subscriber! |
T+30 Days: Have our server enforce a version requirement so users have to update to the latest version where a subscription is required. This requires that we have a client-side mechanism in place early on to ask users to update the app if it’s outdated!
Complexity 2 – Offering multiple subscriptions
Boomerang originates as a web product, where subscriptions are tied to email accounts. Subscribers on the web will have access to the Boomerang app, and vice versa. This means that since Boomerang for iOS app supports multiple email accounts, users need to be able to purchase multiple subscriptions. Combing through the documentation, it doesn’t look like auto-renewable subscriptions can be purchased multiple times, so to work around this, we needed to create a new product on the App Store for each subscription.
To support Gmail and Outlook type accounts, free trial and discount introductory offers, and having a monthly and annual plan, we already had to set up 8 different App Store products:
- Boomerang for Gmail Monthly with Free Trial
- Boomerang for Gmail Annual with Free Trial
- Boomerang for Gmail Monthly with Introductory Discount
- Boomerang for Gmail Annual with Introductory Discount
- Boomerang for Outlook Monthly with Free Trial
- Boomerang for Outlook Annual with Free Trial
- Boomerang for Outlook Monthly with Introductory Discount
- Boomerang for Outlook Annual with Introductory Discount
Now to support up to 3 subscriptions, we have to repeat the above two more times, resulting in 24 different products! 24!
If you’ve interacted with App Store Connect before, you know how long this takes to create products, subscription groups, set prices, introductory offers, identifiers, names, etc. Tip: Make sure you have a good machine and can open a new browser window with as many tabs as you have products!
Because there are duplicates of the same products now (different emails, same subscription), we need to figure out how the client app will know which product to purchase after a user picks a subscription and signs in. It’d be too easy if there was an Apple API to check if the user was subscribed given an App Store product, right? So instead, we have to request an App Store receipt (if any), send it over to our server for validation, and check the receipt’s purchase history for active subscriptions so the client knows which product is available to purchase.
Complexity 3 – Offering a free-trial subscription
The product team wants to offer a free-trial for first time users to match our web product experience. Great, that sounds reasonable, we can just check if the user is eligible for a free trial and show the offer if they are eligible, right? Well, to check for free trial eligibility, you have to:
- Refresh the user’s receipt on the app,
- Validate the receipt with Apple’s servers from our server, and
- Check their purchase history to see if an introductory offer was used before or is being used.
Wait, so to determine if a user is eligible for a free-trial, they must have already made a purchase. But if they made a purchase, doesn’t that mean they are not first-time users and should not be eligible? Also, if we want to refresh the user’s receipt to start this process, that may trigger an Apple sign-in prompt, which would not be a good experience if the user hasn’t committed to making a purchase yet!
After some back and forth, we realized that since Apple has the final say in the system’s purchase prompt, we’ll just display the free trial to everyone and add an eligibility disclaimer and let Apple deal with it. Apple’s purchase confirmation prompt clearly shows if a trial period is included or not, we just wish they exposed this to developers instead of having to go through all those steps!
Complexity 4 – Designing the subscription offer flow
We’ve gathered a lot of loyal users over the years that have been using Boomerang for free, and of course, there are new users every day too. We need to consider both types of users when designing the new subscription offer flow. To figure out when to show the subscription products and offers, here are a few more things to consider:
1. We don’t want users to make any purchases before connecting an email account. This is both to make sure that they don’t purchase something they don’t use, and also to make sure they don’t purchase a subscription that they already have.
2. We also don’t want users to connect an email account, then find out that a subscription purchase is required to continue, so we need to show the subscription page and pricing options first.
2b. If they end up signing into an account with an existing subscription, skip the purchase.
3. Existing Boomerang subscribers should be able to sign in without purchasing a subscription. This flow should fall back to a subscription selection screen if they don’t have a subscription.
4. Nice-to-have: We noticed that fetching products from the App Store could be slow, so if possible, make this network request invisible to the user.
Considering all this, here are flows we settled with. Starting with the introduction screen, we show off Boomerang features while fetching App Store products in the background so product and prices are ready to go by the time the user moves to the next screen:
The two options shown below allow for onboarding a new user where a subscription / free-trial is required to continue, or to let an existing subscriber to sign in. Here’s the flow for starting a new subscription:
And the flow for existing subscribers, including the fallback for if they don’t have a subscription:
Other tips and tricks
Here are some other gotchas to watch out for that didn’t quite make the complexity list as well as some tips and tricks!
- Don’t forget about TestFlight users if you have any! Users on a TestFlight build (internal or external) cannot actually make any purchases, so make sure you have a plan to transition them off TestFlight, remove In-App Purchases, design a sandbox behavior, or are ok with them making free purchases!
- Don’t forget that all the App Store products you created in App Store Connect need to be submitted for review along with the new app! Our first app was actually approved and released without having the products reviewed and so nothing was purchasable! Thankfully existing users could at least dismiss the soft-paywall until we got it fixed but new users were unable to use the app while we were fixing this. An expedited review got this fixed in about a half day.
- We found during production testing that a purchase can fail, succeed, and then be completed outside your app. This happened when Apple needed to re-verify a payment method, which brought the user outside of Boomerang (causing a purchase-failed notification) but upon verifying and purchasing, they weren’t brought back to the app. It’s good to test a couple purchases in production!
- Before turning on paid subscriptions, we only sent 1 warning email to notify users of the new pricing, when we could have sent 1 or 2 more. This needs a fine balance between sending emails with the same content to users vs. making sure everyone got the memo, but in this case we think it’s better to err more to the latter option, which can also help with user reactivation! We got a lot of complaints in the App Store reviews about the sudden subscription requirement without warning when we had both an email warning and an in-app popup.
- Audit purchases on your server after the first renewal period, to make sure users are on the right subscription plan according to their Apple receipts.
- Try to gather as many good reviews as you can before converting to paid, since the change will likely draw some bad reviews!
We hope this is useful if you are looking to add In-App Purchases to your app! We’ve only just scratched the surface, but there’s so much more to In-App Purchases that we didn’t cover like billing retry, grace periods, App Store Server notifications and APIs, promotional offers, in-app events, and more. Now it’s time for us to deal with Search Ads and its complexities!
P.S. We’re hiring! If you are interested in working on these types of projects, come build productivity tools with us! Don’t go back to the office if you don’t want to – we’re fully remote!
P.P.S. As we mentioned at the beginning of the post, it took us 5 years to make a mail client we thought was so good we could ask people to pay for it. If you need to upgrade your mobile email experience, you can get our app here!