An easier way to handle App Store subscriptions
Getting App Store Status Update Notifications (now Server-to-Server Notifications) for in-app subscriptions can be tricky. RENEWAL notifications may not occur as expected, CANCEL does not indicate when auto_renew_status was switched on or off, and it can seem arbitrary when you get older iOS 6 style of receipts or the new style.
Others have described these challenges too:
- statusUpdateNotification not getting renewal notification type from Apple Developer Forums
- Apple Subscription Notifications Are Almost Useless from RevenueCat
- Never Get RENEWAL Notification from StackOverflow
- Server to Server Polling Auto Renewable Subscription from StackOverflow
Superscribe intends to provide a basic “just works”, correct solution for the main subscription use cases.
go get github.com/carpenterscode/superscribe
Superscribe provides a server that both
- scans for expiring subscriptions to check for state changes (like successful renewals) and
- listens for App Store notifications for a limited number of subscription events.
The server needs
- Your App Store shared secret
- A func you define to retrieve expiring subscriptions from the database, called during a scan operation
- A listener to update the database after the scan
See how to connect listeners to Superscribe in example/main.go. This shows how to use the included AppsFlyer listener that attributes events using server-to-server API.
Optionally you can provide
- More listeners, such as for server-side conversion analytics, etc.
srv.AddListener(AnalyticsListener{db, tracker})
- HTTP server request handlers, such as for
200 OK
responses to /healthz pings
srv.HandleFunc("/healthz", func(writer http.ResponseWriter, req *http.Request) {
writer.Write([]byte("OK"))
})
You cannot currently
- Modify the App Store Status Update Notification endpoint. It's currently hardcoded to
/superscribe
, but we can change that in the future. - Use anything more sophisticated than a Go
time.Ticker
.
Generate mocks first
go generate
Test
go test ./... ./receipt
Currently, Superscribe should only be run in a single instance setup. I personally run it on production in a single-pod Kubernetes deployment, but we should figure out how to solve for redundancy and performance by adding some kind of scalability.
There's a lot of unfortunate complexity to subscription management, so the longer term goal is to increase extensibility and robustness.
Most important: Let’s gather real use-cases and requirements to draft a prioritized roadmap.
- Distinguish among first, first year's worth of, and remaining payments. The paid at event could be made more versatile and track 30% vs 15% App Store fee. Or to filter out renewals from first payments.
- Track plan upgrade responses from customers. For instance, moving all monthly subscriptions from 7.99/mo to 9.99/mo.
- Offer a scalable solution. Subscriptions in the local database should only be scanned by a single process, but multiple instances of listeners should be able to coexist. The current 1:1 model limits Superscribe to one instance.