Skip to content

carpenterscode/superscribe

Repository files navigation

Superscribe

Build Status GoDoc

An easier way to handle App Store subscriptions

Overview

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:

Superscribe intends to provide a basic “just works”, correct solution for the main subscription use cases.

Get started

Install

go get github.com/carpenterscode/superscribe

Configure

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

  1. Your App Store shared secret
  2. A func you define to retrieve expiring subscriptions from the database, called during a scan operation
  3. 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.

Usage

Run automated tests

Generate mocks first

go generate

Test

go test ./... ./receipt

Caveats

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.

Future work

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.