What’s new with in-app purchases: WWDC 2022 overview

Suren avatar
Suren

This Tuesday, during WWDC 2022, Apple released the latest updates for in-app purchases. A lot of great updates are still coming, but today we’ll walk you through the improvements that have already been covered: enhancements to StoreKit 2 and App Store Server API. 

So, let’s get started. 

New App Transaction API is released 

Apple has released the new API to verify the purchases of the app. The new API aims to mitigate (or totally prevent) fraud and add more flexibility to the ways you can monetise the app and grant users access.

The new App Transaction API presents the signed information about the purchase and the device with which the purchase was made.

What you should know about the new App Transaction API

1. It’s signed using JWS signature

2. It replaces the app details of the app receipt from the original StoreKit API 

3. StoreKit validates purchases automatically

You still can create your own receipt validation flow, but you’ll need to validate a JWS signature. As Apple highlights, the process is described in the official documentation, so you can easily handle it on your own. 

4. StoreKit automatically refreshes transactions, but in rare cases users can do this manually. 

To provide this functionality, you need to create UI capabilities within the app so users can refresh the app transaction themselves. 

Why it would be better to avoid actions from your side: it’s the same story as with the old API restore function. If the user doesn’t log in and you’re trying to refresh his transaction, he will unexpectedly see the screen that prompts him to authenticate. It might be shocking for users who didn’t take any action with the purchases. 

How to handle switching business models with the new App Transaction API

The new App Transaction API also allows to change your business model easily without affecting the access of existing customers.

App Transaction API allows you to receive the necessary details about the user so you can change your business model from the paid app to free with in-app purchases or subscription monetisation. Previously, you would receive these details by processing the receipt. 

Let’s take a closer look. 

Previously, receipts combined all the information in one section.

Like this: 

Now, the information is divided into separate components in StoreKit: Transaction History and App Transaction.

The first section includes the entire in-app purchase history: the user’s latest transactions, unfinished transactions, and current entitlements. You can receive all this information on your server as well through the App Store API.

The second component, App Transaction, contains all the data you need to understand whether your user has ever purchased your app previously.

So let’s take a look at the scenario of switching your business model from the paid app to the free app with subscriptions. 

Apple has provided a great example of such an app’s timeline. Let’s assume you have two users: the first one has bought the paid app (v2.5) and the second has purchased the subscription after you switched the monetisation model (v8.2). 

The change in your app’s business model means that there will also be changes in your access management logic for the app. 

For instance, you have several features that were previously available for all who purchased your paid app, and now these features are available as non-consumable purchases. Additionally, you’ve added some new cool features that are available with subscriptions. In this case, you should make sure that all your existing customers (v1.0 to <8.0) have access to the premium content they paid for. But you could still suggest that your user buy the new features that become available after switching the business model. Newcomers (v8.0 and higher v8.2) could purchase everything as it is. 

As we mentioned previously, in this case you should distinguish your users: distinguish the ones who bought your paid app from the newcomers.

Let’s take a look at the code that will help us with it: 

On the first line of this code, we get the transaction. Then you should check whether it is verified or not. 

If the transaction is not verified: you can prompt your user to refresh the app transaction and restore the access, simply give the user access to the app but with minimal functionality, or suggest purchasing a subscription. 

If the transaction is verified: you should determine whether this user gets the app.

App Transaction is contained in the field `originalAppVersion` that displays the information about the app version that corresponds to this transaction. If this version is older than the version that you’ve released your new monetisation model, you need to grant the user the needed access. If the version is newer, you should check which access you should grant to your user. 

As you could see, just a few lines of code allow you to receive the verified transaction that contains all the needed details to understand which app version was purchased and when. As I mentioned, it could be possible just by processing of your receipt (that wasn’t too easy).

New Properties in StoreKit

PriceLocale

PriceLocale is now included in product. But what has changed? 

Previously, to show your user the price, you could use displayPrice. This field contained currency and price. There was a price field as well the price without the currency or locale. 

But what about the cases when you’d like to show your user how much he might save if he purchases the annual subscription instead of the monthly one? (And let’s be honest, this is a quite popular mechanic.) What if you also want to show how much he should pay for the annual subscription monthly?

In this case, you can use `priceLocale` to help you add information about the price and currency. The previous version of StoreKit had this functionality, but it was quite unstable – you just needed to fill the SKProduct field. But with the new API you can use just `priceLocale` and show the price wherever you want. 

Server Environment Property 

Environment – server environment in which the transaction was processed. This is an extremely useful property that can be used for testing and analytics purposes. For instance, you could use it to distinguish production purchases from the sandbox purchases so you don’t consider the testing data in your analytics. Previously, this information was available in the receipt and reflected the entire receipt, which was super inconvenient. 

Recent Subscription Start Date 

RecentSubscriptionStartDate represents the most recent period of continuous subscription period (subscription with no more than a 60-day gap between any two subscribed periods).  In other words, it represents the earliest start date of a subscription in a series of auto-renewable subscription purchases that ignores all lapses of paid service shorter than 60 days. 

For instance, if a user purchased the monthly renewable subscription on 8th of June 2021, and then renewed it once in a year (8th of June 2022), and between these periods he didn’t use this app or subscription, this field will contain the first date: 8th of June. 

This is important information to determine the customer cohort that continuously uses your app. By knowing the information about this cohort, you can reward your loyal customers with bonuses and discounts. The information about unsubscribers will help you to take actions to win back lapsed customers.

Sentinel values 

All the new properties that we’ve described above will be available starting iOS15. It will be available if you build your app with Xcode14 (which is available in beta). And all the properties will be available in Production and Sandbox environments. 

What does sentinel values mean? 

If you are testing StoreKit with Xcode and refer to new fields/properties, you’ll receive placeholders values. These are fields with a zero values. 

This is a great screenshot that’ll help you to remember this information.


Btw, you can solve this problem super easily: just update your testing divide to iOS 16.

One more great screenshot that’ll help you to identify these placeholders.

All these new properties are available with App Store Server API and App Store Sever Notifications as well.

SwiftUI + StoreKit updates 

Offer Codes Redeem Modifier in SwiftUI

Offer codes help you to acquire new customers and reward existing ones with discounts, free access, and more. With App Store Connect you can create unique custom codes. You can set a maximum redemption limit and choose whether or not to set an expiration date.

The update is quite simple: offer code redemption sheet has its own view modifier in SwiftUI, so you can easily process redemption flow with just a few lines of code and a binding boolean value. Available with iOS 16. This is the same functionality that was available in StoreKit and UIKit, but now is available in SwiftUI as well.

Updated possibility to request an app review 

The second Swift UI Update is the possibility to request an app review. This also was available in UIKit, but from now on available for SwiftUI as well.

The limitations and best practices are the same: 

  • You can show it max 3 times within a 365 days 
  • You can’t ask people to review the same app version several times
  • You shouldn’t interrupt user flow 
  • You shouldn’t request a necessary review as a result of a user action (completing the game level or achieving the results within the app). The user should have an option to skip this step.

The code example:

New API for StoreKit Messages

Apple released quite an interesting mechanism to display the messages that are related to StoreKit. The simplest example: you increased the price for the purchase and you’d like to show the price increase consent alert to your users. 

So, let’s take a closer look at this flow.

Your app goes to the foreground. StoreKit checks: are there some changes with the App Store? The App Store returns the message info to StoreKit, and StoreKit asks the listener for permission to display the message or defer it (if you’d like to create your own scenarios for these messages to appear). 

But if StoreKit doesn’t include any listener, it will display the message over your app. 

Our advice here is to add listener to not interrupt your user’s flow and to not affect user experience, so the user won’t receive automate screen messages during the app experience. You can ensure customers have a great experience by making sure that messages don’t appear at unexpected times.

The realisation is not that difficult. As Apple highlights, there will be official documentation on how to implement this functionality soon.

Application username

This is a field in which you can add the unique ID of the users from your system just to connect your user with their purchases. Those familiar with StoreKit can tell that this field was available earlier: so what’s the update? 

Well.. you’re right, this field already exists and its title is applicationUsername. It was receiving any string value, but the official documentation recommended sending UUID into this field. 

The update is that StoreKit2 includes the new additional field appAccountToken. The main difference is that this field is geared to receive UUID format only, not any random string value. The great thing is that all UUID strings from the previous StoreKit will be available in the new version of StoreKit as a part of `appAccountToken`.

With StoreKit2 this value will appear in `appAccountToken`. It is a kind of backward compatibility (in case you use UUID in `applicationUsername`). The needed value will appear in StoreKit Transaction, App Store API, and App Store Server Notifications. 

Conclusion 

In this article, we briefly discussed what was presented for in-app purchases during WWDC22, hope it was useful!

We know a thing or two about in-app purchases as Qonversion provides a complete cross-platform infrastructure that allows you to create and restore purchases, validate receipts, and provide your app with an accurate subscription status without the need to build your server. So, If you’d like to learn more about it or have any questions, feel free to ping me in our Slack channel.