Transcript
[ Music ]
>> Good afternoon.
[ Applause ]
My name is Pete Hare and I'm an
engineering manager on the App
Store team here at Apple.
We're here to discuss the best
ways to build your app and
server infrastructure to support
the subscriptions.
I'm going to go over a few
topics here today.
Firstly, we'll discuss the best
ways to actually build your app
and server architecture.
We've got some tips and tricks
around how to enhance the in-app
experience for your user.
My colleague Michael will get up
and talk a bit about reducing
subscriber churn.
And then finally, we've got some
new announcements around
analytics and reporting tools
available to you.
But first up let's talk a bit
about how to build your app and
server infrastructure.
Let's start off by asking a
simple question, what is a
subscription?
Well a subscription gives a user
access to your content or
service by them repeatedly
paying you some amount of money.
When you look at this at the
engineering layer a subscription
is really just a set of
repeating transactions each of
which unlock some subscription
period.
To use subscriptions in your app
there's a couple of things that
you need to do as a developer to
be able to handle these
transactions as they come in.
Let's go through each of these
steps.
Firstly, it starts off with your
app receiving a transaction.
Once your app has received a
transaction you need to go ahead
and verify that it's an
authentic transaction, that
money really has changed hands.
Then it's up to you to update
and maintain that user's
subscription state for ongoing
access to your service.
So let's go into each of these
in a little more detail.
Firstly, let's talk a bit about
receiving that transaction in
your app.
Now whether it's the initial
purchase of a subscription or a
renewal transaction for a
prescription your app is set up
to handle subscriptions and
transactions using the StoreKit
framework.
Now when you are set up to
handle transactions using
StoreKit the App Store will make
these charges on a user's credit
card in the background.
And anytime a transaction occurs
it informs your app of these
transactions via a thing called
the
SKPaymentTransactionsObserver.
This transaction observer object
is really the central piece of
in-app purchases when it comes
to your application.
It's actually just a protocol in
StoreKit, it looks like this and
you can set it on any object.
In this example we're just
setting it on the AppDelegate
itself, but the really important
thing is that you add a
Transaction Observer to the
default payment queue as early
on in the application lifecycle
as possible.
Once you've got a Transaction
Observer registered on the
default payment queue you're
ready to start receiving
transactions as they occur in
the background.
You receive transactions on a
callback in the Transaction
Observed called
updatedTransactions and it's
here that StoreKit will inform
your app of a set of
transactions for you to process.
They can come in various
different states that we're not
going to go completely into in
this talk, but keep an eye out
for a transaction in the
purchased state.
That's a transaction that
StoreKit is telling your app is
ready for verification and
unlocking.
Once you've got a transaction
the purchase state you're ready
to go with that next step, which
is to verify that it is an
authentic transaction.
So when it comes to checking for
authenticity how can you know
that money really has changed
hands?
You use a thing called the App
Store receipt.
The App Store receipt is just
like a receipt you'd get in a
department store, it's a proof
of purchase that a user has
bought something that they say
they've bought.
In this case it's a trusted
record of the initial app
download and any in-app
purchases that have occurred for
this app.
This is a digital document, it's
stored on the user's device, we
provide an API for you to access
it and it's put there by the App
Store.
We also sign this document using
certificates so that you can
check to make sure that it is an
authentic document that's
actually issued by Apple.
And finally, the document is for
your app on that device only.
So if you've worked with
subscriptions before you'll
notice that maybe one user with
multiple devices has receipts
that look slightly different on
each device.
When it comes to actually
verifying this transaction that
your app's been told about the
first step that you need to do
is to actually verify that the
document in question, the App
Store receipt, is authentic.
So how do you do that?
You can do this in two ways.
Firstly, you can use on-device
validation and this is where
directly on the user's device
you can use a series of checks
to check the certificates used
to sign this app and verify that
it's authentic.
Or you can use the technique
called server-to-server
validation.
This second technique is where
you take that binary encoded
receipt data, send it up to your
own server, and then from your
server over to the App Store for
processing.
And the App Store will actually
do those checks for you.
You can use either of these
techniques, but whichever one
you choose it's important not to
use online validation directly
from the user's device, this is
not a secure way of actually
validating this document is
authentic.
But let's compare each of these
two approaches in a little more
detail, especially around
subscription management and
order renewable subscriptions.
Both of these techniques give
you a way to validate that this
is an authentic document.
They also give you access to the
contents of the receipt, any
transactions that have occurred
for this particular user.
But when it comes to auto
renewable subscriptions there's
a few key advantages that
server-to-server receipt
validation actually gives you
over on-device receipt
validation.
Firstly, we include some
additional subscription
information in the response to
that validation check.
You can use this, Michael will
talk about a little later in
this talk.
Your server is always on to
handle those renewal
transactions in the background.
This is really important if
you've got a service with maybe
multiple platforms.
Your server is not susceptible
to a device clock change.
If you're using on-device
receipt validation for
subscription management on the
user's device there's actually
nothing stopping the user from
winding their clock back and
putting themselves into a valid
subscription period, maybe a
free trial that they've actually
lapsed their subscription from.
And finally, it's just a little
simpler.
The server-to-server validation
you're dealing with JSON API,
you don't have to build OpenSSL
or use ASN.1 decoding.
So with all these things in mind
we're really encouraging more
and more people to actually
adopt server-to-server
validation when it comes to
maintaining an auto renewable
subscription state.
If you've got a simple utility
app that doesn't need any kind
of networking you can still use
on-device validation for
subscription management.
And if you're interested in
finding more about that I'd
invite you to check out the
video from last year's events
StoreKit Talk where we went into
more detail about on-device
receipt validation.
But for the purposes of this
talk we're really going to focus
more on the server to server
techniques outlined here.
So let's go back to our example
and see how we can use
server-to-server validation for
this transaction that we're
processing.
Back here in our Transaction
Observer you can access that
binary receipt data using the
App Store receipt URL API on the
main bundle.
Once you have this URL you can
pull out the binary data located
at that spot on the file system
and you can pull out that
receiptData and base64Encode and
this will give you a nice string
that you can send up to your own
server for processing.
You might provide some in-app
networking API for the current
user.
When you're sending that data up
to your server for processing
firstly you'll do this securely
obviously.
You can send it up to maybe a
process transaction endpoint on
your server.
In this endpoint you might have
a user ID associated with the
current user for an account on
your own system.
You can send this receipt data
up to your server and then once
you get that on your server you
can establish a secure
connection to the App Store's
verify receipt endpoint.
And you can send over that
receipt data to the App Store.
Here you can include a password
field, this is just a shared
secret between your app and the
App Store.
You can set this up in App Store
Connect and store it on your
server.
And when you send this receipt
data to the verify receipt
endpoint the verify receipt
endpoint will respond with JSON
payload that looks a little like
this.
The first thing to check when
you're verifying that this
transaction is authentic is this
status field.
This is an indication that Apple
has actually issued this
document in the first place.
Once you've verified that the
status is zero like this you can
check the contents of the
receipt portion of this payload.
This is the decoded version of
that binary data that you just
sent to verify receipt endpoint.
So in here you can do things
like verify that the bundle ID
in this receipt matches your
app's bundle ID.
And then you can inspect the
in-app array, this contains a
list of transactions for this
particular user for your app.
And you can verify that the
product ID associated with this
receipt is the one associated
with your app.
So assuming that these all match
you're determining that this
receipt entitles this particular
user to your subscription
product you're ready to go ahead
now with that third step,
updating the user's subscription
state.
Now in the same way that each
subscription period starts with
a transaction it also ends with
an expiry date.
And the response from verify
receipt tells us each of these
expiry dates for each
transaction.
So looking back at this response
from verify receipt you'll
notice that there's this expires
date field in the transaction
and the response.
Let's bring up the user table
now that you might be saving
this data on your server.
You can take this expires date
from this transaction and
actually populate this into a
field on your own server, maybe
the latest expires date field
for this particular user.
And this field is going to
become the new source of truth
on your server for whether or
not this user is a subscriber.
While you're here you should
also keep track of this other
field, original transaction ID,
and you can save that in the
field called original
transaction ID against this
current user as well.
Well come back to this one in
just a moment as to why that's
important.
But once you've saved these two
bits of information against this
current user on your server
you're ready to go ahead with
the last step, which is to tell
the device that this transaction
has actually passed your
verification checks.
And then when your device gets
this callback it can call Finish
Transaction back down in your
Transaction Observer.
This is a really important step
because finishing the
transactional will actually
clear it out of your payment
queue.
And if you don't call Finish
Transaction it might reappear
there the next time the app
launches for processing.
So make sure you finish every
transaction that begins in
StoreKit.
Once you've finished the
transaction you've got an
updated subscription state in
your server, the user is now
free to enjoy that subscription
period on your service.
Now let's take another look at
that user table I mentioned that
you're storing on your server.
Each user who purchases a
subscription using this setup
will be assigned a unique
original transaction ID, that's
that field that you saved from
the transaction response.
And this identifier essentially
becomes that user's subscription
ID.
And it's important because it
shows up in all subsequent
renewal transactions.
Let's take a look at how this
works.
So let's say that you're
verifying a renewal transaction,
this happens in just the same
way you might use the same
process transaction endpoint on
your own server.
When you do those techniques of
verifying the transactions a
valid one, and you get up to
that stage of updating the
user's subscription state you'll
observe here that there's now
multiple transactions since this
is a renewal transaction.
Now according to your existing
server-side logic this latest
expires date is now a date in
the past, so the user is not
currently a subscriber and you
need to figure out are they
still a subscriber based on the
data in this receipt.
So how can you use this receipt
data and make that deduction?
Well for discovering whether or
not the user has an active
subscription you can pull out
the transactions associated with
that original transaction ID.
And then you can find the
transaction that has the latest
expires date.
Now if you find a date in the
past that's an indication that
this user is no longer a
subscriber anymore.
But if you find a date in the
future that's an indication that
this user is in a valid
subscription period.
So let's look at how this works
in the example that we're going
through.
Grab that original transaction
ID associated with this user and
pull out all the transactions
associated with this
subscription.
Then sort those transactions by
that expires date field and grab
the one that has the latest
expires date.
Now you can take that expires
date and update that latest
expires date field associated
with this user.
And when you do that you're
effectively extending that
user's subscription by another
length of time and your
server-side logic now knows that
the user is in a valid
subscription window.
Of course when you're dealing
with renewal transactions like
this that have come through
StoreKit you still need to
inform the device that it passed
those validation checks.
And have your device, your app
call Finish Transaction back
down in StoreKit again.
So let's say you have this set
up and working correctly.
The App Store is charging the
user's credit card in the
background and you're using
StoreKit to process these
transactions as they come in
through the app.
And then your server is updating
and maintaining this latest
expires date field on your
server.
So you've got that server-side
source of truth as to whether or
not a user is subscribed.
Let's now introduce a slightly
more complex example though to
the mix, which is maybe that you
offer your service through a
website as well.
Now when the user accesses your
subscription service through a
website you know based on that
latest expires date field that
the user is a subscriber.
But as much as we'd like to
think that people use our apps
all the time let's say that the
user doesn't use your app for a
number of days.
And then during this time the
App Store actually successfully
renews a user's subscription in
the background.
When the user tries to access
your servers through your
website that latest expires date
is now out of date because your
server hasn't learned about that
new transaction.
So how can your server know
about this transaction that's
occurred on the App Store?
You use a technique for this
called status polling, this
allows you to discover these
transactions directly from your
server.
In order to get set up to be
able to status poll from your
server you just save a latest
version of that encoded receipt
data that you send up associated
with each user.
And what you can do is you can
treat that encoded data just
like a token.
The reason why it can treat it
like a token is every time you
send up that encoded receipt
data to the verify receipt
endpoint the verify receipt
endpoint doesn't just respond
with a decoded version of that
receipt data, it also includes
any new transactions that have
occurred for this particular
user's subscription.
It's located in a field called
the latest receipt info field in
that JSON response.
And you can use that info to
unlock those new subscription
periods for this particular user
without the app having to launch
at all.
Let's see how this works.
So when you're verifying
transactions just like we saw
before you're sending up that
receipt data.
Now once you've determined that
this transaction in question has
passed those same checks that
you did before you can take that
receipt data and store that in a
field called latest receipt data
against the current user.
And now that you have that
latest receipt data stored,
that's a base64Encode string
with the user.
When it comes time to answer
that question, does my user have
an active subscription you can
just take that latest receipt
data from your server directly
and send it to the verify
receipt endpoint.
You can also include here an
optional flag that's the exclude
old transactions flag, this is
just telling verify receipt that
you don't even want to know
about that decoded version of
the receipt you just want to
find out about any new
transactions.
Verify receipt will respond with
that particular object, the
latest receipt info object.
And inside this object is those
new transactions that have
occurred before this receipt
data was actually generated.
And you can take the expires
date directly from the response
of the latest receipt info
object and update it against the
current user, again extending
them access to that next
subscription window.
And so the user who is on your
website trying to access your
content can now access that next
subscription period all without
the app having to launch with
that new transaction.
If you are using this technique
though status polling it's
important to remember one thing
and that's that when your app
does come back online again
transactions will still appear
through StoreKit in the updated
transactions callback.
And you still should handle
these transactions passing them
up to your server for
verification and finishing them
back down on the user's device
again, even if your server
already knows about them through
a status poll.
We'd encourage you to use that
as an opportunity just to send
up that new latest receipt data
for storage against the current
user on the server.
Now status polling works great
when the user's credit card is
able to be charged, but what if
some subscription period the
user's credit card has some kind
of billing issue and the App
Store isn't able to charge it
for the next subscription
period.
Is this user destined to remain
unsubscribed involuntarily?
Not at all.
When reacting to billing issues
like this you can do three
simple steps.
Firstly, you can observe that
there's been no renewal
transaction for this particular
user, their subscription has now
lapsed.
Secondly, you can direct that
particular user to go and update
their billing info.
And then the third step, when a
renewal transaction occurs
unblock that user immediately
after it happens.
Now, steps one and two are
pretty straightforward using the
status polling techniques that
we just went through, but step
number three here uses a feature
that we actually launched last
year server-to-server
notifications.
Let's walk through this example,
let's say that one subscription
period the App Store has an
error when trying to charge this
user's credit card.
And then you find out about the
fact that there is no new
renewal transaction for this
user through a status poll.
Your server correctly makes the
calculation that this user is
not a subscriber anymore and so
when the user comes along to
access your service through the
website you give them some
appropriate error message about
the fact that their subscription
wasn't able to be renewed.
And you can direct that user to
go and update their billing info
in the App Store.
Now when the user does update
their billing info, maybe they
just need to update an expiry
date or something, two things
happen.
Firstly, the App Store will
actually immediately charge that
user's credit card and make a
successful transaction.
And when the App Store does do
this the second part of what it
does is it sends your server a
direct HTTP post upon the
successful renewal.
And then the payload of this
post includes the new
transaction info for the
transaction that's just
occurred.
You can use that original
transaction ID field located in
the payload to locate which user
this notification is for.
Once you find out which user
you're talking about, well you
can grab that latest expires
date and update it for this new
user giving them access again to
that next subscription period.
And then the user who's probably
still sitting on your website
trying to get access to your
content will be able to
immediately be unlocked since
your server received that push
straight from the App Store.
It's really important to unlock
users in a speedy manner when
this sort of thing happens,
especially when they go to all
that effort for updating their
credit card info manually and
waiting for access to the
servers.
But there's one thing to note
here and that's the notification
is only sent if the subscription
actually lapsed like we just
saw.
To discover successful renewal
transactions you still need to
rely on status polling
techniques we just outlined
before.
But it's really easy to set up
to use server-to-server
notifications.
All you do is enter a URL in App
Store Connect.
This is just an endpoint on your
own server and if you enter it
into App Store Connect the App
Store will begin to send your
server HTTPS posts for these
status change events.
And as we saw included in the
post is that latest transaction
info for the transaction that
triggered it.
You do make sure your server is
ATS in order to receive these,
but it's a really simple step
that you can do to give a bunch
of users a much better
experience.
So those are some tips and
tricks around how to build your
app and server architecture.
Let's talk about three tips that
you can use in your in-app
experience to really enhance the
user's experience.
Firstly, we made the assumption
earlier that the user was signed
in to an account on your own
service.
In order to keep track of each
subscription ID you need this
particular user table located on
your server.
Now when it comes to actually
creating accounts we think it's
best to offer in-app purchase
before an account creation step.
Why is that?
Well as the user it's a much
better experience, you can just
open the app for the first time
and buy the subscription
immediately getting access to
the content you're after.
For you it's better because you
get higher conversion rates,
users don't have to go through
funnels of entering emails and
passwords to be able to get
access to giving you money.
Now you can use the techniques
that we just went through by
using an anonymous account in
these instances.
And you can rely on the original
transaction ID if you need to
associate multiple devices.
If you're using anonymous
accounts like this, when it
comes time down the road to
actually give the user an
account creation flow, you can
just simply take them through a
deanonymization step where you
update those email fields and
maybe other personally
identifiable fields.
So that's tip number one.
Tip number two is around selling
your in-app purchase.
When it comes to selling your
subscription, you can use a
feature that we launched last
year Introductory Pricing.
Now there's an important step
with Introductory Pricing which
is that you need to know at
runtime whether or not a user is
actually eligible for an
introductory price.
And the reason you need to know
this is you have to know which
price to render to your user,
whether to render the normal
StoreKit price or the
introductory offer that you want
to offer a user to get them in
the door.
Now you can set yourself up to
actually know this ahead of time
by monitoring the transactions
that are occurring in the
background as they come in.
Let's see how this works.
When you're verifying
transactions like we just saw
earlier keep an eye out for
these two fields.
The is trial period field and
the is in intro offer period
field.
If either of these fields are
true that's an indication that
an introductory offer or a free
trial was used for this
particular transaction.
And if it was you should keep
track of the product ID in
question against this current
user.
You might store them in a field
called consumedProductDiscounts.
Now if you're keeping track of
which products were used with
introductory offers, when it
comes time to render the price
of some new subscription product
that you want to show your user
this is how you can do it.
You can take those consumed
product discounts saved against
the current user and execute an
SKProductsRequest with them.
And the reason why is that the
response from SKProductRequest
now in iOS 12 includes the
subscription group identifier so
you know which subscription
group this particular product is
from.
And now armed with this
subscription group identifier
you can keep track of that in a
set of consumed group discounts
for this particular user.
So you know which subscription
groups this user has used offers
for.
Now when you want to render the
price string of say product A it
becomes a simpler check.
You can check to see if this
user's list of consumed group
discounts contains the group
identifier for the one you want
to sell them, in this case
product A.
And if it does, that's an
indication that this user has
actually used an introductory
offer here before, so you can
render the normal price string
to this particular user.
But if not, they're still
eligible for that introductory
offer so you can use that
introductory price located on
the SKProductObject.
Now when rendering the price
string nothing's really changed
here it's the same techniques
that you use for rendering any
in-app purchase and I'm not
going to go into too much more
detail here, but I'd encourage
you to check out the video of
the session just before this one
where they talked about
rendering these price strings a
little more dynamically.
For more information about
setting up introductory offers
I'd also recommend you go to the
What's New in App Store Connect
session on Wednesday at 5 p.m.
in hall three.
So that's tip number two around
introductory pricing.
The third tip here is around
subscription management.
You can offer the user upgrades
and downgrades between
subscription tiers right in your
app's UI.
And to do this you can actually
treat it just like selling an
initial subscription.
Now if the subscription you're
selling the user is part of the
same subscription group, so it's
a different tier than the one
the user has already subscribed
to you can basically just create
an SKPayment just like you would
if you were selling them an
initial subscription.
And when you do this StoreKit
actually handles the fact that
it's an upgrade or downgrade for
you.
So you don't have to worry about
that user being subscribed
twice.
Now if you don't want to provide
your own UI for upgrades and
downgrades in your app you can
also just provide a link out to
the App Store subscription
management screen.
We provide a link for you to be
able to get to this screen
directly from your app and here
the user can upgrade, downgrade
or even cancel their
subscription.
Now your app is often the first
place a user will go for
subscription management, to be
able to upgrade, downgrade or
cancel.
So it's a really good idea to
give some kind of link maybe in
your app's settings for a user
to be able to do this.
To actually get to this screen
there's a link available on our
In-App Purchase Programming
Guide and here it is if you
enjoy writing down links.
So these are some simple
techniques you can implement in
your app to give a user a
pleasant experience using
subscriptions.
Next, I'm going to hand it over
to my colleague Michael who's
going to go over some great
techniques for reducing your
subscriber churn.
Thanks.
[ Applause ]
>> Good afternoon, my name is
Michael Gargas and I'm a
technical advocate on the App
Store operations team.
Today I want to talk about
reducing subscriber churn inside
your applications by using some
of the tactics and methods that
Pete just walked you through.
Today we'll cover involuntary
churn and voluntary churn, the
two types of churn you'll see
inside of your subscription
applications, as well as some
ways to win back those
subscribers that you potentially
may have lost or will lose.
First, let's talk about
involuntary churn.
Involuntary churn is the loss of
a subscriber due to a failed
payment or billing issue on the
platform.
Now last year at WWDC we
walked you through what we're
doing in order to minimize
involuntary churn inside of your
applications.
We announced our updated Billing
Retry service where we expanded
our retry duration from 24 hours
to up to 60 days.
We also implemented new retry
strategies and we tuned them
over time to recover more and
more of your subscriptions.
A date to remember is July 13th,
2017 because this is the day
that Apple actively started
recovering subscriptions for
you.
If we look at the performance of
Billing Retry since launch we
can see that our recovery rate
has more than doubled.
And when we look at involuntary
churn we've cut this by over 2%
platform-wide.
[ Applause ]
Now if we look at how our tuning
has impacted the recovery of
subscriptions we can see that
quarter over quarter we've been
able to continue to recover more
and more of your subscriptions.
Now the net result of this has
been 12 million of your
subscriptions recovered since
the launch of Billing Retry.
[ Applause ]
So that's what Apple's doing to
minimize involuntary churn for
you.
But there's also some tactics
that you as a developer can do
to minimize voluntary churn
inside of your subscription
applications.
You can leverage some of the
subscription specific receipt
fields that Pete mentioned
earlier.
You can implement grace periods
and during that time you can
deploy some effective customer
messaging.
So let's take a look at an
example subscription.
Here we can see that our
subscriber was set to renew on
April 26th, however, they
encountered a billing issue.
So in order to let you know that
Apple is actively attempting to
collect funds from that user via
the Billing Retry service we are
going to surface a field in the
JSON response aptly titled is in
billing retry period.
A value of one signifying that
we're attempting to collect
funds for that subscriber.
If we go back to our example of
subscription you can see that
this has been added to JSON
response.
And when you see this in
conjunction with the expires
date this is your signal as a
developer to implement what we
call a grace period.
You may ask yourself what is a
grace period.
A grace period is free
subscription access while in a
billing retry state, however
it's before you have lost that
subscriber, before they've
churned out.
The goal of the grace period is
to improve recovery.
So let's take a look at how we
can do that leveraging some of
the information in the receipt
response.
If we flip back to our example
subscription you can see that
our subscriber is in a billing
retry state and was set to renew
on April 26th.
Here we want to add some
server-side logic to use that
expires date field and the is in
billing retry period in order to
add a period of time, in this
example three days where that
user will continue to have
access to the service and
technically stay subscribed.
Now why would you do this?
Well it's an opportune time to
deploy some effective customer
messaging to contextually
communicate with your
subscribers and let them know
that there may be an issue with
their subscription.
You may want to do things like
ask them to update their payment
method or have them restate the
value proposition of the
subscription offering that
they're subscribed to.
And during this time you can
offer limited service as well,
such as a browse but not watch
experience in an entertainment
app.
Here we can see Peak, a
subscription developer on the
App Store.
Peak is leveraging the Billing
Retry status fields in order to
surface a contextual message to
their subscribers letting them
know that there's been an issue
with their subscription.
When engaged upon they're taken
to an additional screen which
clearly states what the issue is
and how they can resolve it.
But it would be really effective
if from this screen you could
drive that user or subscriber
directly to our systems to
update their payment details.
So I'm excited today to announce
that we have two new URLs coming
shortly after WWDC this
year, one to drive users
directly to update their billing
information and the others to
take them to manage their
subscriptions as Pete alluded to
earlier for upgrades, downgrades
and crossgrades.
[ Applause ]
With that being said, a lot of
developers will ask well when
are we seeing our users be
recovered.
And on average we see the
majority of users recovered
within the first seven days of
entering a Billing Retry state
on the platform.
This might be a time to offer a
full access grace period because
we see a lot of users
self-recovering during this
time.
You may want to deploy that
customer messaging towards the
tail end of this to bring in
some of those subscribers that
might've taken longer to come
back into your application.
Let's flip back to our example
subscription.
What happens if this is
effective and we're able to
recover these customers?
When a retry attempt is
successful the date of the retry
or recovery becomes the new
subscription anniversary date
moving forward and this will be
reflected in JSON response when
validating that successful
transaction and finishing it.
But we're not going to stop
there we're also going to deploy
our server-to-server
notifications so that you can
immediately unlock access on all
platforms and close the loop
with your customer letting them
know hey you're all set.
So that's involuntary churn
where the customer didn't
technically make a choice to
unsubscribe from your
application.
But what is voluntary churn?
Voluntary churn is the loss of a
subscriber due to customer
choice, either cancellation or
refund requests.
To be clear, this user actively
made the choice to leave your
subscription offering.
So what can you do as a
developer to minimize voluntary
churn inside of your
applications?
Well Pete walked you through how
to status poll earlier and you
can implement that to get some
key subscription details about
your users and when you get that
information you can use it to
offer attractive alternative
subscription offerings to
potentially save that user.
So let's talk a little bit more
about status polling.
With the release of
server-to-server notifications
there's really only two key
reasons that you still need to
status poll.
The first is understanding will
my subscriber churn in the
subsequent subscription period
and the second being has my
subscriber renewed.
We often get asked when should I
status poll as a developer, when
should I try to catch those
users and see their subscription
state changes.
The most effective times that we
see are doing that status poll
at the beginning or end of a
subscription period.
By deploying this responsibly
you're most likely going to
catch most users that may want
to voluntarily churn from your
subscription offering.
But when you status poll you'll
also get access to some
additional subscriber status
fields.
And you may want to take those
fields and save the decoded JSON
response from the verify receipt
call in the user tables on your
databases.
Or alternatively, you can parse
out specific fields such as the
Billing Retry Status in order to
segment your customers and maybe
understand those that are in a
retry state and those that are
not.
But the signal to understand if
a customer will voluntarily
churn is shown via a field
called auto renew status.
Auto renew status will let you
know with a value of one that
that subscriber will return in
the subsequent subscription
period and a value of zero
letting you know that they will
voluntarily churn at their next
subscription anniversary date.
Let's see what this would look
like in our example
subscription.
Here we have a subscriber
purchased on March 26th and
they've made the choice to
disable auto renew via the
manage subscription setting
screen.
Now coincidentally, we status
polled shortly after this
happened and we were able to see
via the receipt response that
the auto renew status has
changed to zero.
It's at this point that you can
update your user tables on your
database or on your server and
segment that customer as a
potential voluntary churning
customer.
If we go back to the example
subscription we've status
polled, we've captured this
customer might leave, so what
should we do?
As a developer this is your
opportunity to present an
attractive downgrade offer
potentially in the same
subscription group.
Here we can see Peak trying to
save that user by potentially
having them take a lesser term
or a lesser price subscription
of a different duration or maybe
a different offering.
If that subscriber decides to
engage with this the same way
that Pete showed you by
surfacing upgrades and
downgrades within your
applications we want to let you
know what product they will
renew on in the subsequent
period.
We do this via the auto renew
product ID field in the JSON
response.
So this differs from product ID
in that this is what the next
offering will be after that
subscriber renews.
Here we can see in the example
subscription our subscriber has
elected to downgrade instead of
churn out.
We've changed the auto renew
status to one and we've added
auto renew product ID.
It would also be beneficial to
be notified of this change
immediately, so for this we'll
also send a server-to-server
notification letting you know
that your subscriber did change
their renewal preference.
This is useful if you want to
maybe state the differing
service levels between what
they're currently subscribed to
and what they will have in the
subsequent period.
Now it's impossible to run a
100% retention subscription
business, so it's important to
understand how you could
possibly win back some of those
subscribers that you might have
lost.
A win back is reengaging
subscribers after they've
churned by showing them
resubscription offers or
potentially surveying them to
understand why they've left.
If we look at our example
subscription let's see what a
voluntary cancellation would
look like and how we can
leverage that inside of our app.
Here our user has elected to
cancel via AppleCare.
In order to let you know we're
going to surface a cancellation
date field in the JSON response.
This is your signal to
understand this customer has
contacted AppleCare and either
canceled or requested a refund.
But as a developer you would
want to know this information
immediately.
For this we'll deploy a
server-to-server notification.
This is important because you'll
immediately want to shut off
access to those users on all
platforms and potentially
prompting them to see
alternative subscription offers.
Now after this user has churned
it would be important to easily
segment between those that have
voluntarily chosen to
unsubscribe and those that have
involuntarily been unsubscribed
due to a payment issue or
billing issue.
So for that we have the field
expiration intent in the JSON
response.
Now to be clear, this will only
show up after the subscription
has lapsed.
And we really want to focus on
two key values, the first being
value one which signifies
voluntary churn, the second
signifying involuntary churn
with a value of two.
If we flip back to our example
subscription where our customer
canceled via AppleCare you can
see that we've added the
expiration intent field to the
receipt response with a value of
one.
So what do you do as a developer
when you see your subscribers in
this state after they've already
churned and you've segmented
between those that have
voluntarily and involuntarily
churned?
Well for voluntary you may want
to survey those subscribers who
have opted into an account on
your system.
You can ask them maybe why the
service wasn't appropriate for
them and what you can do to
tailor it moving forward to
provide a better experience for
them or other users.
Additionally, you can always
just show alternative
subscription products
potentially within the same
group because if they
re-subscribe you want to
continue accruing your time
towards that 85/15 revenue
share.
Here we can see Peak when a user
has voluntarily churned being
shown a resubscription offer, in
this case a 60% discount.
For involuntary churn since the
user did not actively make the
choice to unsubscribe it's
appropriate to just show the
same or alternative subscription
products.
You may want to leave some
persistent messaging if that
user is logged in inside the
application experience letting
them know that they have lapsed,
but that they can always come
back.
And you may also want to deploy
a limited subscription
experience, such as a browse but
not watch experience in an
entertainment app.
Here we can see Tinder, when
users interact with pro level or
subscription level features they
are continually prompted to
subscribe.
So in summary, if you take
anything away from this section
on reducing subscriber churn
it's that you should be
leveraging these subscription
receipt fields effectively.
You can then implement status
polling to understand when your
subscribers may voluntarily
churn.
You can then use that status
polling to deploy some targeted
and effective customer
messaging.
And then to close it out,
presenting contextual
subscription offers to these
users to hopefully win them back
or prevent them from churning in
the first place.
So with that I'd like to hand it
back to my colleague Pete to
discuss analytics and reporting.
Thank you.
[ Applause ]
>> Thanks Michael.
If you haven't implemented
handling of these JSON fields
yet we highly recommend you try
it and watch the great effect it
has on your retention rates.
It's not often as engineers we
get the chance to make such
simple architectural tweaks that
can have such a big effect on a
business' revenue, so take a
look.
Now we've got some great new
updates today in the areas of
analytics and reporting.
Located in App Store Connect the
sales and trends section
contains a huge amount of useful
information.
Now you can get even more
insight into your app's
performance.
This existing subscription
summary dashboard now includes
monitoring for subscriptions
that are in those Billing Retry
windows.
This is great for gaining
insight into your subscriber
behavior and to determine the
most effective amount of time to
offer those grace periods for
like Michael just talked about.
This year we're also introducing
a brand-new dashboard for
subscription retention.
This page offers a glance at how
your introductory prices are
going, as well as how many of
the users are subscribed to the
higher proceeds rate, that's
that 85 to 15% split you get
when a user has been subscribed
for a year.
The dashboard includes new
graphs to help you quickly
identify which subscription
cohorts are the highest
performing and you can monitor
your subscription performance
over time and compare your app's
performance across different
territories.
Now all this new information is
not just available inside the
App Store Connect report, but
it's now available through the
new App Store Connect API.
The report data here is
available to you daily and you
can script your own setups to
import this maybe into your own
data warehouses for further
analysis.
We're not going to go into any
more information on the App
Store Connect API here, but I
really recommend you check out
the automating App Store Connect
session in the hall three on
Thursday at 3 p.m., there's some
really exciting enhancements in
the area of automation.
Now we've talked a bit about
what you can get from receipts
and what you can get from these
App Store Connect reports.
So as a bit of a summary, App
Store receipts are useful for
validating those StoreKit
transactions and updating user
subscription states, maintaining
the state on your server.
And you can also use them to
understand individual subscriber
behavior just like Michael
showed you.
For App Store Connect reports
it's for a slightly different
reason, they're better at that
macrolevel analysis, maybe
understanding subscription
pathways of users of your app
and maybe most importantly,
understanding how much money is
going to get deposited into your
bank account for your
subscriptions.
Now we've covered a lot of
topics here today, but as a bit
of a summary remember that
server-side state management
offers you much more flexibility
when it comes to managing
subscriptions.
If you haven't done it yet add
that URL to receive
notifications from the App
Store.
Consider offering an
introductory price in your app,
it's a great way to get users in
the door to your own
subscriptions.
Add some simple messaging to
reduce subscriber churn, using
those fields that Michael walked
us through.
And for users that have actually
lapsed offer some alternative
subscription options maybe to
win them back.
Finally, remember to check out
these new reporting tools
available in App Store Connect.
For more information on this
session and for the video, this
has been session 705.
We're also going to be in the
labs this week right after this
and also on Thursday at 9 a.m.
we'll have engineers from the
StoreKit team and for App Store
Connect ready to answer any
questions that you might have
about engineering subscriptions.
Thanks a lot.
[ Applause ]