Transcript
[ Music ]
[ Applause ]
>> Good morning!
Welcome to In-App Purchases and
Using Server-to-Server
Notifications.
My name is Dana DuBois, and I'm
an App Store engineering
manager.
We'll talk about a number of
things today.
First I'm going to start off
about what's new in StoreKit.
What have we changed since we
were here last year?
Then I'm going to hand it off to
my colleague Tori, and she's
going to give you everything you
need to know about
Server-to-Server Notifications,
and how you can make sure you
have the latest information
about your subscription
customers on your backend.
Next up, Manjeet is going to
walk through the different
billing events during the
subscription lifecycle.
And then, finally, he's going to
walk you through what you need
to know to reduce involuntary
churn, and keep your
subscription customers in your
service.
So, first.
What's new in StoreKit?
Well, this spring we introduced
subscription offers.
Subscription offers is a feature
that we introduced that gives
you a tool to retain existing
subscribers as well as win back
subscribers who used to be in
the service.
You can achieve this by having
up to 10 different active offers
per subscription, that will give
you a discount or free service
that you can give to your
customers.
Your app decides what to present
and to whom.
It's completely up to you.
This is such a great feature,
and such a big feature, that we
actually have a dedicated
session to that later today,
right here at 2 o'clock.
If you have subscriptions in
your service, I highly recommend
you check that out.
So, what else is new in
StoreKit?
Well, this summer, we're
announcing that we've introduced
the SKStorefront.
SKStorefront is how we're
actually exposing to you, the
developer, the storefront that
the user has set their App Store
to.
This allows you to present the
right content to your customers.
What do you want to merchandise
to your customers all around the
world?
You can use the SKStorefront to
get specific territory for that
customer on their device.
This is the same way that the
App Store exposes content.
And, this API gives you the
storefront that the App Store is
currently set to.
One thing to keep in mind is
that this API returns a
device-specific cached value for
that storefront.
And, it can change over time, so
there's some stuff you need to
think about while you're
interfacing with the
SKStorefront.
So, let's get into the code, and
see how this will all work.
So, if you're interfacing with
StoreKit today, you're already
have a delegate on the
SKPaymentQueue.
We've added on that, the ability
to get a parameter that returns
the current cached value for the
storefront.
Just .storefront, and that'll
give you the value.
Because it can change, and
because it's device-specific, it
is possible, though unlikely,
that it will be nil.
So, you need to check for that
in your app, and make sure you
do the right thing.
Once you have that storefront,
right on that API, is a country
code.
And, that's a 3-letter,
ISO-standard value for
territories and countries all
around the world.
And, that'll tell you exactly
what the App Store is set to on
that device.
And, that's really it.
That'll allow you then to take
that country code, and
merchandise the right content to
your customers.
But, as I said, it can change
over time.
So, let's go a little deeper
into the code, and see what else
you need to think about.
Here we have an example of some
code where you're taking your
product identifiers that you
fetch from your backend, passing
it in and then trying to
determine if you should fetch
the metadata, do an SKProduct
request to determine if you
should show that content or not.
So, what the developer has done
there is, fetch that metadata
from their backend, and did a
call to say, hey, is this
storefront valid for that code?
And then, you can see here,
right before you fetch product
info, you would call shouldShow.
If that returns true, add that
identifier to the list of things
you're going to make an
SKProduct request on.
You should do that before you
make the SKProduct request,
because if you're not going to
merchandise that product, it's
more efficient not to actually
fetch the product-- the product
metadata.
But, as I said before, it can
change over time.
The users could actually switch
accounts, or even-- it's even
possible within the same account
to go into the App Store and
browse different storefronts.
Developers will do this a lot
when they actually want to see
their app in different
territories around the world,
see what it looks like.
See how it's doing.
There's ways of doing that in
the App Store.
So, we want to make sure you
have the latest information in
your running app.
So, on the SKPayment transaction
observer, we added a new
paymentQueueDidChange event that
you can listen for, right inside
your app.
That passes in the payment
queue.
When you get that, you go
queue.storefront, and get the
new value for what that
storefront is.
And, again, it's a new
storefront.
So, you want to reload all the
content specific to that new
store front.
You might actually have
different content that you want
to merchandise based on where
that user is in the world.
So, again, call shouldShow.
Determine if you should, and
fetch product information for
it.
So, what happens when you're
doing a purchase?
You've merchandised some
content, the user's about to go
buy it, and normally everything
will go fine.
But, if the user is actually in
a different storefront from what
their device was set to, it is
possible that the payment queue
will change storefronts in the
middle of that transaction.
So, we've given you a
paymentQueue delegate that
allows you to listen to
paymentQueue: shouldContinue: in
newStorefront.
This is your chance to
double-check, should I allow
this purchase to happen in this
new storefront?
And, again use that same
shouldShow functionality, where
you've listed all your product
identifiers, and you know all
the territories that those
products are available in.
Just-- if it returns true, allow
the payment to continue.
To make sure that it's the best
user experience, we want this to
return fast, so you shouldn't
make a server-side call in the
middle of paymentQueue:
shouldContinue: newStorefront.
You should have this information
cached on your device, what's
available in the territories,
ready to go when the payment's
happening.
That way, you can return real
quick, the user can continue
their purchase, or, if you're
returning no, you can actually
inform the user why it's not
valid in the new storefront.
So, as I said, maybe it's not
available in the new territory.
So, what do you do then?
Well, when that happens, in your
paymentQueue:
updatedTransactions delegate
call, we'll return an
SKStoreProductNotAvailable
error.
This will inform you that you've
just told us that you shouldn't
allow this transaction to happen
in that new storefront.
And, here's your chance to
present a dialog.
Or, merchandise some other piece
of content that might be
equivalent in the new
storefront.
Show an alert, update the UI, do
what you need to do right then
and there.
So, that's SKStorefront.
What else are we introducing?
Well, in iOS 11, 11.2 and tvOS
11.2, and macOS 10.13.2, we
introduced app pre-orders.
This has been a great feature
that developers have used all,
you know, around the world, to
actually get interest in their
apps before they're available in
the store.
And, we're excited to announce
that we're introducing that with
watchOS 6.0 this year, so you
can market your apps right to
the Watch, and gain interest
ahead of time, like having them
be available for pre-order.
But, we're also doing one more
thing this year.
And, coming soon, we're actually
going to signal inside the app
receipt, if the app was
purchased as a pre-order.
So, you'll know which of your
customers have actually
pre-ordered the app.
And, you can use that to, you
know, give them great messages,
saying thank you for
pre-ordering my app.
Or, if you want to unlock some
additional content as a thank
you to some of your best
customers, you can use that
information.
That'll be available in the
receipt.
And, the great thing about the
receipt is that this will go
back to iOS 11, 12, all the way
back in time.
It's available in the receipt.
[ Applause ]
So, those are some of the things
that have changed with StoreKit,
and in-app purchases since we
were here last year.
Next up, I'm excited to hand it
off to my colleague Tori, and
she's going to talk all about
Server-to-Server Notifications.
Tori?
[ Applause ]
>> Hi everyone.
My name's Tori, and I'm very
excited to be here today to talk
to you about Server-to-Server
Notifications.
We have several new features
that we want to bring to the
server-to-server notification,
and I want to do an in-depth
talk with you on how you can use
these to effectively monitor
your subscription events.
But, before we get into all
that, let's first take a look at
what Server-to-Server
Notifications are, and how you
can set up your servers to
receive them.
So, Server-to-Server
Notifications are an HTTP POST
we send from our server to
yours, with a JSON body.
You might recognize these by
their previous name,
statusUpdateNotifications.
Server-to-server notifications
are incredibly useful for
getting of-the-moment updates on
your subscription events, and
for using them so win back
customers in cases like
subscription offers.
Once you've determined which
endpoint you want to receive
your Server-to-Server
Notifications at, all you have
to do is return a 200 response
from that endpoint to indicate a
successfully received message.
However, should you not return a
200 response, we will retry up
to three times to resend the
notification to you.
Once you have determined this
endpoint, you first have to set
it up in App Store Connect.
You can find this place on your
app's App Information page, in
the Subscription Status URL
section.
In addition to setting up your
endpoint in App Store Connect,
there are certain security
requirements which the
connection must adhere to in
order for you to successfully
receive these notifications.
Basically, this all sums up to,
the connection must be App
Transport Security, or ATS,
compliant.
Now, this means a few things.
First, the certificate must be
issued by a trusted certificate
authority.
The Transport Layer Security
version, or TLS version, must be
TLS 1.2.
You must use one of the provided
symmetric ciphers, and the
certificate must be signed and
hashed using an algorithm which
is SHA-256 or greater.
I hope with all this
information, you have a better
understanding of what
Server-to-Server Notifications
are, and how you can set them
up.
Should you need more
information, you can look up the
documentation for
statusUpdateNotifications on
developer.apple.com.
So, now that we've looked into
what Server-to-Server
Notifications are, and how you
can receive them, I'm very
excited to talk to you about the
new features and new
notification types we are
bringing to Server-to-Server
Notifications.
So, as we were thinking about
some new features we could add
to the notification, we were
taking a look at the receipt
fields currently in the
notification, latest receipt,
and latest receipt info.
We noticed that these receipts,
while useful, only give you
information about the latest
in-app purchase.
So, we were thinking how much
more useful it would be if we
could give you your entire
subscription history when we
send you the server-to-server
notification.
For this reason, we are bringing
the unified receipt to the
server-to-server notification.
[ Applause ]
So, as a review, the unified
receipt contains the history of
subscription purchases for your
subscription.
Previously, this incredibly
valuable information could only
be obtained through hitting
verifyReceipt.
The two receipt fields in the
notification right now, latest
receipt, and latest receipt info
provide an encoded and decoded
transactional receipt about the
latest in-app purchase.
Starting in the fall, you'll
begin to see one new field in
the server-to-server
notification.
We have decided to call this
unified receipt, and it will
contain almost exactly what you
expect to get from verified
receipt.
With the addition of unified
receipt to the server-to-server
notification, in most cases,
this will make latest receipt
and latest receipt info no
longer needed.
However, there is one important
caveat we must call out here.
This receipt that we are
generating for you is not tied
to a specific install of an app
on a device, like the receipts
you are used to receiving as the
result of a buy.
For this reason, the receipt
should always be stored on your
server, and never locally on a
device.
So, with that out of the way,
let's take a look at what you
can expect to find in the
unified receipt in the
server-to-server notification.
The first field you will find in
this JSON object is the latest
receipt.
This is an encoded unified
receipt, which we have just
generated for you, and you can
use this to hit verified receipt
later, if you should need it.
You will also find the latest
receipt info.
This contains an array of
subscription purchases for your
subscription, with metadata
about them to help you track
what has been going on with your
subscriber.
You will also find the pending
renewal info.
This contains information about
the upcoming renewal for your
subscription, such as if the
customer is in a price increase
flow, or they have entered a
billing retry period.
We will also include the status
of the receipt, and the
environment the receipt was
produced in, either sandbox, or
production.
We chose to name the fields this
way because this mirrors what
you expect to receive from
verify receipt.
So, hopefully you can reuse your
parsing logic there to make the
transition easier here.
However, latest receipt info
will be limited to the 100
latest in-app purchases.
So, should you need more
information that this, you can
always hit verify receipt with
the provided encoded receipt.
So, let's look at the
notification types we currently
have.
There are currently four
existing notification types.
INITIAL BUY, INTERACTIVE
RENEWAL, DID CHANGE RENEWAL
PREFERENCES, and CANCEL.
And, we are adding four more.
DID CHANGE RENEWAL STATUS, DID
FAIL TO RENEW, DID RECOVER, and
PRICE INCREASE CONSENT.
[ Applause ]
Now, let's take a quick look at
each of those four new
notification types, so we can
get an idea of why they are
sent.
First, let's look at DID CHANGE
RENEWAL STATUS.
This is sent when the user
toggles auto-renew on or off.
You should actually be receiving
this notification right now, so
make sure that you're looking
for it if you are currently
using our Server-to-Server
Notifications.
We will soon be adding a
notification type called DID
FAIL TO RENEW.
We will send this to you when a
subscription fails auto-renew at
the first attempt to renew in a
subscription period.
You will start to see this
notification in the fall.
Hand-in-hand with DID FAIL TO
RENEW comes DID RECOVER.
DID RECOVER will be sent when we
recover billing of your
subscription during the billing
retry period.
This will also start to appear
in the fall.
Should you receive DID RECOVER,
you should have recently
received DID FAIL TO RENEW.
And, you can know that billing
of your subscription was
successfully recovered.
If you are currently using our
Server-to-Server Notifications,
you may notice that we will be
sending DID RECOVER when we
currently send our renewal
notification type.
The plan is for DID RECOVER to
eventually replace RENEWAL as it
is a bit more aptly named, but
for a period, when we start
sending DID RECOVER, we will
send you both DID RECOVER and
RENEWAL to give you time to
adjust to the change.
Finally, we're adding a fourth
notification type, PRICE
INCREASE CONSENT.
PRICE INCREASE CONSENT will be
sent to you when we detect that
one of your subscribers has
entered a price increase flow,
which requires their consent in
order for them to continue
renewing their subscription.
With this notification, comes a
new field in the JSON payload,
price increase effective date.
This is the date by which the
customer must agree to the price
increase in order for them to
continue renewing.
You may also expect to see this
notification in the fall.
So now that we've taken a look
into what's new in
Server-to-Server Notifications,
I'm really excited to talk to
you about how you can handle all
eight of our notification types
so you are getting the most out
of each notification when you
receive it.
So, first, let's take a quick
overview of our existing
notification types.
INITIAL BUY, INTERACTIVE
RENEWAL, DID CHANGE RENEWAL
PREFERENCES, and CANCEL.
We're going to take a moment to
take a deep-dive into each of
these notification types, but
before we do that, I want you to
notice one trend up here on this
chart.
You'll notice that in the JSON
payload, we're asking you to
look for the original
transaction id for each
notification type.
This is because the original
transaction id is considered a
unique identifier for your
subscription.
And, keeping track of this will
help you to link subsequent
events back to the initial
purchase of your subscription.
Now, let's imagine for a moment
that you have a potential
subscriber.
Let's call him John, and he is
interested in purchasing your
subscription.
Let's take a walk through
decisions that John makes
concerning his subscription, and
what notifications you will
receive along the way.
So, the first notification type
you can expect to receive for a
subscription is the INITIAL BUY.
When John first purchases his
subscription, we will send you
an INITIAL BUY notification.
Upon receiving this
notification, you can update the
customer status to something
like "active" or "subscribed" on
your server, and provide service
for the newly purchased
subscription.
In this notification type, there
are four fields that I want you
to look for in the JSON payload.
The first of these is the
purchase date.
This is in milliseconds
since epoch, and it will
tell you the exact date and time
that your customer has purchased
your subscription.
You should next look for the
original transaction id.
As I mentioned, this is a unique
identifier for your
subscription, and keeping track
of this now will let you link
subsequent notifications back to
this initial buy.
You should also check for the
web order line item id.
This is considered a unique
identifier for each subscription
period and should you need to
hit verify receipt after
receiving this notification, it
will link this notification to
an entry in the verifyReceipt
array.
Finally, you should look for the
product id.
The product id will tell you
exactly which product your new
customer has subscribed to.
So, after John has been using
his subscription for a while, he
decides that he wants to upgrade
his service to a higher tier.
We consider this a renewal in
the foreground, so we will send
you an INTERACTIVE RENEWAL
notification type.
Because an upgrade gives the
customer access to the higher
tier immediately, we will also
send you a CANCEL notification
type for the lower tier
subscription, which we have
canceled.
However, should a customer
resubscribe after churn, you
will receive only an INTERACTIVE
RENEWAL notification type.
In this notification, there are
four more fields you should look
for in the JSON payload.
The first of these will be the
purchase date.
This will tell you the exact
date and time that your customer
either resubscribed to this
subscription or upgraded their
service.
You should again be checking for
the original transaction id to
link this back to the original
subscription, as well as the web
order line item id.
This is the unique identifier
for each subscription period,
and it will help you to link
this notification to an entry in
the verifyReceipt array.
Finally, check for the product
id.
This will tell you the exact
product that your customer has
re-subscribed to or upgraded
their service to.
A little later down the line,
John decides to downgrade his
subscription to a more basic
tier.
In this case, we send you a DID
CHANGE RENEWAL PREFERENCES
notification type.
Upon receiving this
notification, you can update the
customer's subscription status
on your server to a more basic
tier.
In this notification type, there
are two fields that I want you
to look out for.
The first of these is the auto
renew product id.
Because a subscription downgrade
does not take place until the
end of the subscription period,
this will tell you exactly which
product your customer will
auto-renew at when it comes time
for renewal.
You should again be checking for
the original transaction id to
link this notification back to
the original subscription.
Now, unfortunately, a little
later, John gets on the phone
with customer support and
decides to cancel his
subscription.
In this case, we will send you a
CANCEL notification type.
As I mentioned earlier, when a
customer upgrades their
subscription, you will also
receive a CANCEL plus an
INTERACTIVE RENEWAL, where the
CANCEL signifies the lower tier
subscription which was canceled.
In this notification type, I
want you to look for three
fields.
First, you should look for the
cancellation date.
This will tell you the exact
date and time that your customer
decided to cancel their
subscription.
You should still be looking for
the original transaction id to
link this back to the original
subscription purchase, as well
as the product id, to know
exactly which product your
customer has canceled.
So, now that we've looked at all
of our existing notification
types, let's give the same
treatment to the four new
notification types that I
introduced earlier.
These are DID CHANGE RENEWAL
STATUS, DID FAIL TO RENEW, DID
RECOVER, and PRICE INCREASE
CONSENT.
In these notification types, you
still want to be looking for the
original transaction id in each
of the JSON payloads.
As I mentioned earlier, this is
because it is a unique
identifier for your subscription
and will help you to link all of
your notifications together.
Now, let's revisit John.
One day he is scrolling through
his managed subscriptions page,
and decides to turn auto-renew
back on for your subscription.
In this case, we will send you a
DID CHANGE RENEWAL STATUS
notification type.
You will also receive this
notification if a customer
decides to turn auto-renew off.
Upon receiving this
notification, you can update the
customer subscription status on
your end to reflect the changes.
You can optionally deploy
retention strategies to keep the
customer, if you see that they
have turned auto-renew off.
In this notification type, there
are four more fields that you
should look for and mark down.
The first of these is the auto
renew status change date.
This tells you the exact date
and time that your customer's
auto-renew status changed.
You should check for auto-renew
status.
This will tell you the direction
of the auto-renew toggle.
Should you see the auto renew
status has a value of true, you
can know that your customer has
turned auto-renew back on, and
intends to continue buying your
subscription.
You should again be checking for
the original transaction id, to
link this back to the original
subscription purchase, as well
as the product id, to see
exactly which product your
customer has turned auto-renew
on or off for.
As we are trying to bill John
for his subscription during the
auto-renew period, we
unfortunately encounter a
billing error.
In this case, we will send you a
DID FAIL TO RENEW on our first
attempt to renew for that
subscription period.
Upon receiving this
notification, you can optionally
choose to suspend service for
your customer.
You can also update the customer
subscription status to something
like "active" or "billing
re-try," depending on the value
of the fields you see in the
JSON payload.
So now, let's take a look at
that.
The first field you should be
looking for here is is in
billing retry period.
This has a value of 0 or 1, and
will tell you if we are actively
trying to recover billing of
this subscription for you.
Should you see that this field
has a value of 1, you can know
that we are trying to recover
billing of your subscription in
the billing re-try period.
You should still be checking for
the original transaction id to
link this back to the original
subscription, as well as the
expires date.
This will tell you the exact
date and time that we attempted
to auto-renew your subscription,
and it failed.
Fortunately, during the billing
re-try period, the billing issue
with John's subscription was
resolved, and we are able to
recover billing of his
subscription.
In this case, we send you a DID
RECOVER notification type.
As a reminder, DID RECOVER is
replacing our RENEWAL
notification type, which we
currently send at this time.
Upon receiving this notification
type, you can restore service
for the recovered subscription,
and update your customer's
status to something like
"active" or "subscribed," or
whatever you use to denote an
active subscriber.
In this notification type, there
are a few more fields that I
want you to look for in the
payload.
You should first check for the
purchase date.
This will tell you exactly when
we were able to recover billing
of this subscription.
You should again check for the
original transaction id, as this
will tell you exactly which
subscription we recovered
billing for, as it is the unique
identifier for the subscription.
Finally, look for the expires
date.
This will tell you the date and
time that this new subscription
period will expire.
And, you can expect us to
attempt to auto-renew again.
Now, let's suppose that you, the
developer, decide to increase
the price of your subscription.
When we check for a price
increase for a subscription, 7
days before a weekly
subscription renewal, 10 days
before a monthly subscription
renewal, and 30 days before an
annual subscription renewal, and
we see that you wish to raise
the price, we will send you a
PRICE INCREASE CONSENT
notification for your customer.
Upon receiving this
notification, you can update the
user status on your end to
something like "price increase."
And, optionally, you can deploy
in-app messaging to prompt your
customer to consent to the price
increase.
Note that we will also email and
send push notifications to the
customer to prompt them to
consent to this price increase.
In this notification type, there
are a few more fields that I
want you to look for.
First, you should look for the
price consent status.
This will tell you if your
customer has already consented
to your price increase.
However, because we are sending
this notification to you, almost
as soon as we detect the price
increase, you should expect in
most cases that this value will
be 0, or that the customer has
not yet consented.
You should again be checking for
the original transaction id to
link this notification back to
the original subscription.
Finally, I want you to look for
the expires date.
This will tell you the date and
time that this subscription
period will expire.
And, by that time, your customer
will have had to consented to
the price increase.
So, now that we've taken a look
at what's new to
Server-to-Server Notifications,
and what you can do to handle
these notifications, when you
receive them, I'm going to
invite Manjeet Chawla onstage to
talk to you about subscription
lifecycle, and reducing churn.
[ Applause ]
>> Good morning.
My name is Manjeet Chawla, and
I'm on the App Store commerce
scene.
I'm really excited to be here
today, and talk to you guys
about how you can use the new
and improved Server-to-Server
Notifications to identify
billing events through a
subscription lifecycle that may
impact your customer's
subscription status.
So, what does the lifecycle of a
subscription look like?
Now, you may start acquiring new
customers by offering them a
free trial, or an introductory
price to attract them to your
service, and let the users try
your service before paying the
full price.
Next, you keep them engaged to
your service by providing them
constant updates to your
content.
And, finally, you try to retain
them as active subscribers by
minimizing churn.
Now, we all know that during
this lifecycle, there's a number
of different billing events that
can occur for most of your
subscribers.
And, today, you're probably
calling the verifyReceipt
endpoint for all your
subscribers to get these billing
event changes.
Now, we know that this is not
efficient, and can be costly
over time, as your subscription
business grows.
But, the improvements that we
saw earlier to Server-to-Server
Notifications, you no longer
have to rely on the receipts to
reflect these billing event
changes.
So, let's talk more about how
you can use the new
Server-to-Server Notifications
to detect these billing events,
and build the best subscription
experience for your customers.
So, let's start with the initial
purchase of a subscription.
Now, we all know that this
initial purchase unlocks content
over a set period of time.
When the customer purchases
their subscription in your app,
you will receive a transaction
through StoreKit on the device,
and a receipt associated to that
transaction.
At the same time, you'll receive
a new notification called
INITIAL BUY for this newly
purchased subscription.
Using this notification, you can
identify a newly purchased
subscriber that has never
purchased your subscription
before.
Now, you hang onto that initial
buy notification JSON, and at
the same time, you send your
receipt from the device to your
server over a secure connection.
And then, to the verifyReceipt
endpoint to validate the
contents of the receipt.
In the response that you get
back from the App Store, you
then check for the contents of
the JSON, and you update your
user database by looking for
information for the latest
purchase that the user made.
Finally, that notification that
you stored previously, you can
link the response that you got
from the App Store through this
verifyReceipt, and link that to
the initial buy notification by
using original transaction id,
and the web order line item id.
Now, when the subscription is
ready for renewal, the App Store
will automatically renew the
subscription for you in the
background.
And, the next time the user
launches their app on the
device, you'll receive a new
transaction, and a receipt
associated to that transaction.
You, again, base64-encode that
receipt, and send that securely
to your server.
And, let's say your user is
consuming their service on a
different platform, and you
don't want to rely on the user
launching the app to detect this
renewal.
You can also use the receipt
data that you stored previously
from the initial purchase, and
send that to your server.
Next, you send that to the
verifyReceipt endpoint, and
check for the renewal
transaction in the JSON
response.
In the response, you can
validate the latest renewal for
that user, and you update the
latest expires date, based on
that subscription.
And, finally, you keep service
on for the customer as the
subscription successfully
renewed.
Note that for this event, there
is no server-to-server
notification.
So you have to call
verifyReceipt based on the
information that you have from
the initial purchase to check
for the renewal transaction.
Now, let's say that the customer
has been loving your service,
and they enjoy their basic
subscription service, and they
decide to upgrade your service
to your premium product, maybe a
higher tier of service.
Now, for this upgrade, you'll
receive a CANCEL notification
from the App Store on your
server.
And, in the content of the JSON,
there will be a cancellation
date notifying you that the App
Store has canceled the previous
subscription for the user.
Followed by the CANCEL, you'll
also receive an INTERACTIVE
RENEWAL notification on your
server.
Use this notification to update
your users' database with the
date of the upgrade.
So, now you know that this user
has upgraded their subscription
to a higher tier service, or a
premium product.
And, finally, you unlock the
premium content for the user in
the app.
Now, at some point, the customer
decides that this content isn't
right for them, and they want to
cancel their subscription.
They do this by turning off
auto-renew inside Manage
Subscription settings on the
device.
Now, today, you might be relying
on the receipt to reflect the
latest renewal status.
You may even be calling
verifyReceipt for all your
customers, just to get the
renewal status of their latest
subscription.
Now, we talked about this
earlier.
Tori mentioned the new
notification, by using that you
no longer have to rely on
verifyReceipt for that renewal
status change.
And now, you get the DID CHANGE
RENEWAL STATUS notification any
time a user turns off or on
their auto-renew status from the
Manage Subscriptions settings.
You use this event to update the
renewal status of the
subscription to false, because
in this case the user turned off
auto-renew.
And, you update their
subscription status.
Now, let's say that you don't
receive any other notifications
for this user until the end of
their subscription period.
You can safely assume that their
subscription has now churned at
the end of their current
subscription period.
So, you can update the
subscription status for your
user as "inactive" or "churned."
Now, over time, as your
subscribers will churn out, you
want to try and win them back by
giving them an attractive offer,
either a discounted price, or
maybe even a free trial.
We launched a new feature
recently called Subscription
Offers that allows you to give
that discounted price, or a free
trial, to keep existing
subscribers, or win back
previously churned subscribers.
We have a session on
Subscription Offers later today,
where my colleagues will go
through best practices in
implementing subscription
offers.
And, the different use cases on
how you can use subscription
offers to improve your retention
numbers.
Now, let's take a look at a
slightly different case, where
the user had no intention to
cancel your subscription, but
the App Store was unable to
recover or renew the
subscription on the user's
behalf.
Maybe the user's credit card was
invalid, or maybe they did not
have sufficient funds in their
account.
For this event, the App Store
will now send you a DID FAIL TO
RENEW notification.
Using this notification, you
know that the user's
subscription failed to renew due
to a billing issue.
And, you can update your
subscription status for that
customer to "inactive" or
"churned."
You use this notification to
show them a message inside the
app, letting them know that
their subscription has expired.
Now, for billing-related issues,
the App Store automatically
makes several attempts to renew
the user's subscription over
time.
If an attempt succeeds, and if
you're able to charge the
customer for that subscription,
you'll now receive a DID RECOVER
notification.
So, using this notification, you
update the user database for
that customer to "subscribed,"
and you note the new expires
date for that newly renewed
subscription.
And, you re-enable service for
that customer.
So, now we saw in the last
example, that the App Store
makes several attempts to renew
subscriptions over a period of
time.
Now, this happens automatically
for you, but how can you as a
developer respond to these
attempts, and what can you do on
your end to reduce involuntary
churn?
Last year, in Engineering
Subscriptions, we talked about
our extended billing re-try
logic that attempts to renew the
subscription over a period of
time.
This is deployed when a
subscription fails to renew due
to a billing issue.
And, since launch, we have been
making constant updates and
tuning to our strategies to
optimize recoveries.
We're also looking at advanced
machine learning models to
improve how we recover
subscriptions across the
platform.
Now, as we look at performance
since launch, you can see that
we're recovering more than 77%
of subscriptions that failed due
to a billing issue.
And, by recovering these
subscriptions, we have been able
to reduce the overall
involuntary churn to less than
2% across the platform.
[ Applause ]
And, with all these updates and
improvements that we've made to
our billing re-try strategies,
we have been able to recover
over 46 million of your
subscriptions.
[ Applause ]
Now, these subscriptions would
have churned otherwise, and
users had no intention to cancel
their service.
Users were renewing and enjoying
their service, and they did not
want to cancel their
subscription.
And, we see across the platform
that more than half of these
subscriptions are still active.
Now, as we look at how we are
recovering these subscriptions
over time, over the period of 60
days, you can see that we
recover more than 77% of
subscriptions that failed due to
a billing issue over the period
of 60 days.
And, more than 80% of these
recoveries happen in the first
16 days.
So, what happens when we recover
these subscriptions?
First, you reenable service, as
Tori mentioned earlier, with the
new notifications.
You may re-enable service for
the customers next time that
they try to access their
service.
We start a new billing cycle for
that subscription from the date
of recovery.
And, the days of paid service
that the customers were
accumulating toward that higher
revenue share, 85/15, resumes
from that day of recovery.
So, if you were offering service
to customers during this period
from the day they started
billing re-try to the day of
recovery, you're probably
missing out on revenue for those
days.
How can we improve that?
So, this fall, I'm excited to
announce that we're launching a
new feature that will allow you
to offer a grace period, a
billing grace period, that
allows additional time for
customers while they're enjoying
their service, they have access
to that paid content.
And, it allows you, the
developer to get additional
revenue for any service that you
provide during those days.
[ Applause ]
Now, this creates a better
experience for all your
customers, who recovered
naturally over a period of time,
because they never expressed an
intent to cancel.
This also recovers customers who
maybe had a temporary credit
card hold on their account.
Now, let's take a look at how
you can implement this feature.
Well, it's really easy.
It takes three simple steps to
implement a billing grace
period.
First, you opt-in via App Store
Connect to offer pre-configured
durations for grace period.
Now, based on the recovery data
that we saw earlier, we're going
to start with 6 days for weekly
subscriptions, and 16 days for
all other durations.
Next, you look for a new field
in the verifyReceipt response,
or in the notification.
This will allow you to know the
latest expiry date for your
service.
And, you keep service on for
customers during the period.
Now, you may be thinking, as a
developer, why should you opt-in
to offer a billing grace period?
Well, there's a number of
benefits.
First, your customers never
intended to cancel your
subscription, so they enjoy
accessing your service without
any interruptions.
This also allows you, or your
customers to maintain their
existing billing cycle, as we
recover their subscription
during this billing grace
period.
And it enables you, the
developer, to earn additional
revenue for the service that you
provide during this billing
grace period.
And, as we saw earlier, it
allows customers to accumulate
those 85/15 higher revenue share
days of paid service at a faster
rate.
I highly encourage you to look
into grace period for your
subscriptions when we launch
this later this fall.
Now, in addition to offering a
grace period, what are some of
the other things that you can do
to reduce overall involuntary
churn, and improve recoveries?
Here we see an example, where
inside the app, by showing
contextual messaging to your
customers who are in the billing
re-try state, you can let them
know that their subscription has
failed to renew due to a billing
issue.
And, if you were offering a
grace period, you can focus your
messaging on any grace period
service that you are providing
to your customers.
Now, you can be creative with
how you devise this messaging.
It can be towards the end of the
grace period.
Maybe you are providing premium
content, and they will lose
content at the end of that grace
period.
So, highlighting the premium
content that they're going to
lose at the end of the grace
period will help you recover
those subscriptions.
Here we see an app, Foodvisor,
showing a message to customers
in billing re-try, and showing
them the remaining duration for
the premium content.
Now, within this message, you
can also embed a deep link to
the payment details page, where
the customers can then go and
resolve any billing issues.
As you can see, we've recently
updated this Payment Details
page to allow a customer to have
up to 10 different payment
methods on account.
Now, in addition to providing
easier payment management
options to customers, this also
helps the App Store to reduce
overall involuntary churn by
charging alternate payment
methods on file.
Now, we covered a lot of topics
today in this session.
But, just to summarize, we
talked about Subscription
Offers, our new feature that we
launched recently that allows
you to reduce voluntary churn by
giving customers a discounted
price, or a free trial to retain
their subscription.
Dana walked us through the code
to implement a new API called
SKStorefront which you can use
to display the right content to
your customers around the world.
We talked about some receipt
changes that are coming soon,
that allow you to reward your
loyal customers who pre-ordered
the app, maybe by giving them a
starting balance of a game.
And, if you haven't already done
this, check out the
Server-to-Server Notifications,
and add that URL in App Store
Connect to get notified for the
billing events from the App
Store.
We talked about grace period,
and how you can provide a
billing grace period to improve
recoveries for customers that
their subscriptions failed to
renew because of a billing
issue.
And, we talked about contextual
messaging, that you can display
inside the app to recover more
of your subscriptions.
For more information on this
session, and the video for this
session, look up Session 302.
And, later this afternoon, my
colleagues will talk about
subscription offers best
practices.
They'll tell you how to
implement subscription offers,
and the different use cases for
using subscription offers to
reduce voluntary churn.
And, we'll be around in the lab
to answer any questions you may
have about these features.
Thank you and have a great rest
of your afternoon.
[ Applause ]