A primer and key pain points of implementing auto-renewing subscriptions on the App Store. Presentation for Toronto Area Cocoa and Web Objects (TACOW) meetup.
2. Agenda
Why: Choose a Subscription Business Model?
Who: Am I To Know?
What: You need to know to get started?
How: Do you avoid some pain points?
Where: Are we having beers?
3. Why Choose Subscriptions?
Fastest growing business model
on the App Store
Over a 80% of all apps are free,
up from 67% in 2014
Generated $10B in revenue in
2017, estimated $75B in 2022
App Store Revenue (%)
0
20
40
60
80
100
2010 2012 2015 2018
Paid Free+IAP Free+Subscrption
6. Why Choose Subscriptions?
PAID SUBSCRIPTION
Periodic impulse in revenue
Slow build to the sum of
the impulses every 3-4
months recurring
Launch
Apple Design Award
App Store Feature
7. Why Choose Subscriptions?
Recurring Revenue
Higher price points and fewer customers
Build meaningful relationships with good customers
Dont hold back big features for new major versions
Apple said so
Everybody is doing it
8. Why Choose Subscriptions?
Are subscriptions right for me?
O鍖ering ongoing value
Is the model right for the potential customers
Do you have ongoing infrastructure costs
Popular Categories:
Content, Utilities, Dating, Productivity, Creative
9. Who Am I To Know?
First implemented Non-Renewing Subscriptions in 2011
11. Who Am I To Know?
First implemented Non-Renewable Subscriptions in 2011
Auto-renewing plans for Flixel hosting service in 2014
Included the app unlock in 2015 before it was legal
Worked around a number of limitations that have since been
added to the App Store (i.e., price changes)
Lucky for you there are still lots of limitations and workarounds
12. What Are The Basics
Create your Auto-renewing plans in App Store Connect
Initiate StoreKit at launch and fetch products
Show localized plans in-app with the conspicuous disclaimer
ALWAYS END YOUR TRANSACTIONS
Provide a mechanism to restore subscription and non-
consumable IAPs
16. Subscription Groups
Made up of subscriptions of di鍖erent levels and durations
Helps ensure multiple subscriptions are not active
Rank the subscriptions in descending order by most access
Ranking de鍖nes rules for upgrade, crossgrade, downgrade
22. Localized Pricing
open class SKProduct : NSObject {
@available(iOS 3.0, *)
open var localizedDescription: String { get }
@available(iOS 3.0, *)
open var localizedTitle: String { get }
@available(iOS 3.0, *)
open var price: NSDecimalNumber { get }
@available(iOS 3.0, *)
open var priceLocale: Locale { get }
23. Localized Pricing
extension SKProduct {
/// - returns: The cost of the product formatted in the local
currency.
var regularPrice: String? {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = self.priceLocale
return formatter.string(from: self.price)
}
}
27. Purchase Completes
Once the transaction state changes to .purchased you can
store the subscription transaction to unlock
What about if a renewal occurs?
What if the user deletes the app?
What if you have more than one app or a web service?
Can use the receipt instead of restoring the transactions
28. Complete Transactions
Once veri鍖ed on-device or sent the receipt to your server call
SKPaymentQueue.default().finishTransaction(_:)
If you dont StoreKit will keep posting the transaction
Apple is more likely to refund the transaction if you dont
29. let receiptURL = Bundle.main.appStoreReceiptURL
Receipt is in PKCS Cryptographic Container & ASN.1 encoded
Need to build a static OpenSSL, asn1c, etc to verify it
Bundle Apple Root CA Certi鍖cate
Not provided by Apple on purpose no single point of failure
On-Device Receipt Validation
30. Server Side Receipt Validation
If you can, have your server manage receipt veri鍖cation
Send the BASE64 binary encoded receipt data and store it
Server sends it to Apple server that responds with JSON
payload of the receipt and a latest version of receipt data
JSON includes additional information about subscription state
31. Server Side Receipt Validation
If you have multiple apps/platforms you must use this method
App Transport Security is required
Di鍖erent endpoints for Production and Sandbox environments
https://buy.itunes.apple.com/verifyReceipt
https://sandbox.itunes.apple.com/verifyReceipt
Dont call from the device
Status code to indicate if you should use the other environment
32. Additional Receipt Fields
auto_renew_status indicates if the customer has cancelled
auto_renew_product_id renewal product could be di鍖erent
price_consent_status when you change the price
is_in_billing_retry_period indicate past due to user
expiration_intent is voluntary, billing, price increase, etc.
original_transaction_id your primary key to the subscription
34. Managing Server-to-Server
Your server can receive push subscription status updates
General App Information > Subscription Status URL
Only one endpoint, so you have to forward sandbox requests
Di鍖erent data structure containing partial change data
Delivery is not guaranteed
Poll all receipts daily to ensure auto-renewal and cancelations are
synchronized
35. Ways to Increase Conversions
Promoted In-App Purchases
Auto-renewing Subscription O鍖ers
Introductory O鍖ers
NEW: Promotional O鍖ers
Handling Past Due user experience
36. Promoted IAPs
Can promote up to 20 IAPs
Give customers browsing the App Store a one-tap buy button
Needs unique images
Shows up in search results (n.b., ASO marketers)
Another reason you need to initialize StoreKit at launch
37. Promoted IAPs
func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment
payment: SKPayment, for product: SKProduct) -> Bool
Always return false now or risk rejection
Hold on to the SKPayment
Display Product, PRICE, and Conspicuous Disclaimer
Have the user sign-in/up if necessary
Then add the payment to the payment queue
39. Subscription Offers
Introductory O鍖ers
Free Trial, Pay as you go, Pay up front
Unique by (Territory, Plan)
Displayed on Promoted IAP on the App Store
SKProduct.introductoryPrice
41. Subscription Offers
Promotional O鍖ers
Up to 10 o鍖ers per plan to existing or churned subscribers
You decide which are shown
Not displayed on the App Store avoid IAP pollution
Requires a server to determine eligibility & generate signature
SKProduct.discounts
42. Past Due User Experience
On-device or before last year you dont know user is past due
Apple used to cancel after 24 hours, now it is 60 days
Up to you how to limit access
Clearly inform the user that they are past due
Show a button that opens
https://apps.apple.com/account/billing
43. How Do You Avoid Some Pain
Cancelled is not what you think it means
Converting a Paid app to Free+Subscription
New App Auto-Renewing Subscription Propagation
Have I mentioned the Conspicuous Disclaimer?
44. What Cancelled Means
Another reason to poll nightly is that a transaction in the receipt
can change
cancellation_date_ms, cancellation_reason
Means refunded and you should remove access immediately
46. How To Know If Churned
On-device: if the latest transaction in the receipt end date is in
the past now
Server-side : check pending_renewal_info for
expiration_intent
50. New App with Subscriptions
Turns out that auto-renewing subscriptions arent added to the
production environment until the app is live
Most of the time this propagates to all stores quickly
But
51. New App with Subscriptions
Activation of the In-App Purchase identi鍖ers may lag up to 48
hours following the activation of the application