---
title: "Privacy-focused in-app subscriptions"
description: "How to set up a bare-bones implementation of the Purchases SDK"
language: "en"
publishedAt: "2021-04-13T09:48:00Z"
updatedAt: "2021-04-13T09:48:00Z"
authors:
  - name: "Cody Kerns"
    url: "https://www.revenuecat.com/blog/author/cody-kerns"
category: "Engineering"
categoryUrl: "https://www.revenuecat.com/blog/engineering"
readingTime: 8
canonical: "https://www.revenuecat.com/blog/engineering/privacy-focused-subscriptions-in-your-swift-app"
---

# Privacy-focused in-app subscriptions

How to set up a bare-bones implementation of the Purchases SDK

## Table of contents

- [Subscriptions with RevenueCat](#subscriptions-with-revenuecat)
  - [What is Magic Weather?](#what-is-magic-weather)
  - [Configuring the SDK](#configuring-the-sdk)
- [Check Subscription Status](#check-subscription-status)
- [Fetch Offerings, Make Purchases, Unlock Entitlements](#fetch-offerings-make-purchases-unlock-entitlements)
- [App Store Connect](#app-store-connect)
- [Providing Customer Support](#providing-customer-support)

Over the last few years, customer privacy has become an increasingly important consideration for developers. Between the regular occurrence of data breaches and the implementation of GDPR, app developers have to be more and more conscientious about what data they collect and how that data is stored and used.

Apple recently put a spotlight on this issue by implementing the App Tracking Transparency framework and requiring developers to disclose information about data collection and use within their App Store listing. Today’s users are more concerned about privacy than ever before—and can find out what data your app collects before they even download it.

When you add subscriptions to your app with RevenueCat, you’ll have to start disclosing some of this data collection to your customers. But rest assured, this doesn’t mean your users’ data isn’t private or secure. And this disclosure isn’t just required for developers using RevenueCat; you’ll have to disclose your data collection even if you run your own subscription status server.

The fact is, the only way to keep your users’ subscription status secure is to validate your receipts from a server, which requires some minimum data disclosures.

***Can’t I just do receipt validation locally? Why do I have to send user purchase data to a server?*****‍**

Apple [strongly recommends](https://developer.apple.com/documentation/storekit/in-app_purchase/validating_receipts_with_the_app_store) against performing receipt validation locally. It makes it easy for bad actors to intercept the connection and perform a man-in-the-middle attack. Local receipt validation also removes the ability to sync purchases between iOS and Android and you’ll have to update your app every time you make changes to the products you sell.

Of course, if you are performing receipt validation directly from the device, you won’t need to disclose any purchase data collection. This is a trade-off, and you’ll have to decide for yourself what makes the most sense for you.

Are you willing to allow your premium features and content to be accessed by jailbroken devices or run the risk of someone hijacking the connection between your app and Apple? For some, the answer to this question may genuinely be yes. If that’s the case for you, check out [SwiftyStoreKit ](https://github.com/tikhop/TPInAppReceipt)and [local validation implementations](https://developer.apple.com/documentation/storekit/in-app_purchase/validating_receipts_with_the_app_store).

Going that route means you’ll be sacrificing other features, though, including super-simple purchase logic, customer support tools, and robust reporting/metrics—plus privacy for your users.

## Subscriptions with RevenueCat

In this blog post, I’ll walk you through a bare-minimum implementation of subscriptions in a Swift app, using a stripped-down version of the RevenueCat Magic Weather sample app as a project template. We’ll use RevenueCat’s Purchases SDK for subscription status and purchase logic, and we’ll discuss how to keep your users’ data private while also taking advantage of the benefits mentioned above.

### **What is Magic Weather?**

Magic Weather is RevenueCat’s sample app that was built to be as consistent as possible across platforms, while still taking into account each platform’s differences. In this post, we’ll be starting with a stripped-down version of the Swift sample app that’s ready for subscriptions. Of course, if your app is ready for subscriptions too, you can follow along.

You can download the [project template here](https://github.com/RevenueCat-Samples/blog-magic-weather-privacy).

To follow along with this tutorial, you’ll need to have the Purchases SDK installed. If you haven’t already done this, [go here](https://docs.revenuecat.com/docs/installation) for installation instructions.

Additionally, if you haven’t already set up your products, check out our [guide on Products, Packages, Offerings, and Entitlements](https://docs.revenuecat.com/docs/entitlements)**.**

### Configuring the SDK

Before we get started, let’s enable debug logs. Debug logs provide important context from the Purchases SDK and will help us debug any issues that come up down the line. Enable debug logs by calling this method as early as possible in your app’s lifecycle, like in the AppDelegate’s `didFinishLaunchingWithOptions` method:

‍

```javascript
Purchases.debugLogsEnabled = true
```

One of the easiest ways to keep your users’ data private is to take advantage of RevenueCat’s anonymous user identifiers. Automatically generated by the SDK, these IDs keep your users anonymous.

With the RevenueCat SDK, using an anonymous ID is simple. Just call `configure` with your API key, leaving out the `appUserId` variable—or just pass `nil`. Add the following underneath the line that we used to enable debug logs:

‍

```javascript
Purchases.configure(withAPIKey: "api_key")
```

A new, randomized, and anonymous user identifier has now been created by the SDK, and this user’s purchases will be attached to this anonymous ID.

## Check Subscription Status

Let’s jump to our `WeatherViewController.swift` file and find the `performMagic` method. Currently, this method automatically changes our fake weather forecast, but we need to make sure we’re checking the user’s subscription status beforehand.

Replace this line:

```javascript
self.setWeatherData(SampleWeatherData.generateSampleData(for: self.currentEnvironment))
```

With this:

```javascript
Purchases.shared.purchaserInfo { (purchaserInfo, error) in
    if purchaserInfo?.entitlements[Constants.entitlementID]?.isActive == true {
        self.setWeatherData(SampleWeatherData.generateSampleData(for: self.currentEnvironment))
    } else {
        let main = UIStoryboard(name: "Paywall", bundle: nil).instantiateInitialViewController()!
        self.present(main, animated: true, completion: nil)
    }
}
```

‍

This will fetch our `PurchaserInfo` from the Purchases SDK and determine whether our anonymous user has an active entitlement. If they do, we’ll magically change the weather—if not, we’ll present them with a paywall. Since the Purchases SDK caches the user’s `PurchaserInfo` for a few minutes, it’s safe to call this fetch method as often as you need!

We haven’t made any purchases yet, so the user won’t have an active entitlement. Let’s fix that!

## Fetch Offerings, Make Purchases, Unlock Entitlements

It’s time to fetch your product offering from RevenueCat and display it in your app’s paywall. In the project template, open up the `PaywallViewController.swift` file. RevenueCat organizes products into Offerings and Packages. Let’s fetch your Offering and reload the `tableView` that displays our Packages.


In `viewDidLoad`, add the following after the super method:

```javascript
Purchases.shared.offerings { (offerings, error) in
    self.offering = offerings?.current
    self.tableView.reloadData()
}
```

Our paywall uses this current Offering to create a cell for each available Package, then on cell selection, calls `purchasePackage` via the SDK. The rest of the purchase logic is already implemented in this sample, so if you scroll down to the end of the `PaywallViewController.swift` file, you’ll see that purchase method in action in the tableView’s `didSelectRowAt` method:

```javascript
Purchases.shared.purchasePackage(package) { (transaction, purchaserInfo, error, userCancelled) in
\/\/ \u2026 additional implementation
}
```

The Purchases SDK handles the rest of the purchase logic, including interacting directly with StoreKit and syncing the user’s receipt to RevenueCat’s backend, unlocking any associated entitlements. Of course, this all happens anonymously. After a purchase, the paywall will be dismissed, and you can start changing the forecast.

Now let’s visit [App Store Connect](https://appstoreconnect.apple.com) to set up the privacy disclosures that Apple requires for our app’s App Store listing.

## App Store Connect

Find your app in App Store Connect, and select **App Privacy** in the sidebar.

Since we’re only using anonymous identifiers, and we aren’t collecting any PII, we only need to let Apple know of one data type that we are collecting.

Find **Purchases** in the data type list, and check the box.

![](https://cdn.sanity.io/images/c3qnx9b0/production/d50b5ea9bc3389bd0082e4f3ff959c1190623599-1120x168.png)

Click **Save**. Then you’ll need to set up additional information about what RevenueCat does with the Purchase History data.

All RevenueCat users must select the Analytics and App Functionality options. This data isn’t tied to a user’s identity, since we use anonymous IDs—but these are basic functionalities of the RevenueCat dashboard that must be disclosed.

- Selecting Analytics ensures compliance for RevenueCat’s dashboard features, including Customer History, Charts, and Experiments.
- Selecting App Functionality ensures compliance for RevenueCat’s receipt validation and enables features via Entitlements

![](https://cdn.sanity.io/images/c3qnx9b0/production/2d5693b5ea4bdd299ea81c7ca912031a142d0262-1134x1382.png)

Once you’ve selected those options, click **Next**.

Then, Apple will ask you if the purchase history data we discussed previously is linked to a user’s identity. Since we’re using anonymous IDs, you can safely select **No**:

![](https://cdn.sanity.io/images/c3qnx9b0/production/5d490eeda3cc8c1b307cb6e18ddaa5eb434a67e2-1118x244.png)

Click **Next**. Apple will now give some definitions and examples of what it means to use data for tracking purposes. Since we’re not tracking our users with this purchase data, select **No** again, then click **Save**:

![](https://cdn.sanity.io/images/c3qnx9b0/production/d1e16b7a67f666e1aec95a615f165ad9e261ea37-1096x218.png)

As far as Apple’s privacy requirements, you’re all set! Your data privacy settings should now look like this:

![](https://cdn.sanity.io/images/c3qnx9b0/production/2fc21d9b4d1f7440782386ac7ede5babb6a92e51-1182x370.png)

It’s important to note that there are other situations where you may need to disclose additional privacy details—for example, if you use any of RevenueCat’s analytics integrations. Take a look at our support [guide on app privacy](https://appstoreconnect.apple.com) for more information.

## Providing Customer Support

You’ve made sure your users’ data is private, but what happens if they have a problem with their subscription? Ideally, you should have a way to view each user in the RevenueCat dashboard to diagnose any issues or grant promotional subscriptions.

Displaying a user’s anonymous app user ID somewhere in your app’s UI enables you to provide this support.

Once again, the Purchases SDK provides an easy way to access this ID:

```javascript
Purchases.appUserId
```

Simply show this ID in your app’s settings (or if you’re using the Magic Weather sample app, the User tab) and give your users the option to share this with you. *Pro tip: Automatically copy the ID to the user’s clipboard when they tap it—this will save a lot of headache!*

Don’t worry, this doesn’t fall under [Apple’s definition of data collection](https://developer.apple.com/app-store/app-privacy-details/#optional-disclosure), as it’s optional for the user to provide this data, and it’s not part of your app’s core functionality.

## Summary

That’s it! At this point you’re making purchases and tracking subscription status—and your users are anonymous and private. You’re also able to provide customer support to your users via the RevenueCat dashboard without violating their privacy.

Want more sample projects to learn how to implement the Purchases SDK? Check out the [RevenueCat docs ](https://docs.revenuecat.com/docs/sample-apps)for details on how to get set up on every platform—including iOS, Android, React Native, and Flutter!

‍
