Skip to Content
Course content

245: In-App Purchase Compliance Checklist

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen a lot of great apps get stalled at the finish line—not because the code was buggy, but because the developer treated the App Store Review process like a formality rather than a legal audit. When it comes to In-App Purchases (IAP), Apple isn't just checking if your code works; they're checking if you're being honest and fair to the user. If you miss one tiny compliance detail, your app gets rejected, and you're back to square one, wasting three days of your life waiting for a re-review.

The "Just-Buy-It" Button Shortcut

The naive way to build a paywall—and I've seen this in plenty of early-stage projects—is to create a simple view with a "Go Pro" button. You trigger the product.purchase() call, the system sheet pops up, the user pays, and you unlock the feature. It's clean, it's minimal, and from a purely technical standpoint, it works perfectly. In our hypothetical photo app, "PixelPerfect," you might just have a button that says "Unlock All Filters for $4.99."

The problem is that this approach ignores the "human" and "legal" side of the App Store Guidelines. You've provided no context on what the subscription period is (is it monthly? yearly? lifetime?), there's no way for a user who deleted the app to get their purchase back, and there's no link to your terms of service. To a reviewer, this looks like a "dark pattern" designed to trick users into spending money without full disclosure.

Why the Reviewer Will Reject You

If you submit the "Just-Buy-It" approach, you'll likely get a rejection under Guideline 3.1.1. The reviewer will tell you that your app "fails to provide a Restore button" or that the "subscription terms are not clearly visible." It sounds pedantic, but it's non-negotiable. If a user buys a lifetime license for PixelPerfect on their iPhone, then buys a new iPad, they expect those filters to be there. If you haven't implemented a restoreCompletedTransactions() flow and provided a visible button for it, you're creating a support nightmare for yourself and a violation for Apple.

Then there's the legal legwork. Apple requires that any app offering auto-renewable subscriptions must have a link to the Terms of Use (EULA) and a Privacy Policy directly on the purchase page. You can't just bury these in a "Settings" menu three levels deep; they need to be accessible at the point of purchase.

Building a Compliant Storefront

The better way is to think of your paywall as a contract. You want to be explicitly clear about what the user is signing up for to avoid disputes and rejections. For PixelPerfect, this means transforming that single button into a structured storefront. I always recommend adding a "Subscription Details" section that explicitly states the billing frequency (e.g., "Billed annually at $29.99") and a clear list of the benefits the user receives.

Crucially, you need to add a "Restore Purchases" button. I usually place this in a smaller font at the bottom of the screen. It doesn't need to be the focal point—you don't want to distract from the "Buy" button—but it must be discoverable. Underneath that, add two simple buttons or links: "Terms of Use" and "Privacy Policy." These should open a SFSafariViewController pointing to your hosted documents.

The trade-off here is a slightly more cluttered UI. You're adding three or four elements that don't "sell" the product. However, the cost of a slightly busier screen is negligible compared to the cost of a rejected build and a delayed launch. By being transparent, you aren't just satisfying a reviewer; you're building trust with your users. They know exactly what they're paying for and know they won't lose their access if they switch devices.




📋 Practical Task

Implementing the PixelPerfect Restore and Legal Footer

You have been handed a StoreView.swift file for the PixelPerfect app. Currently, it only contains a single Button("Unlock All Filters") that triggers the purchase flow. Your task is to bring this view into compliance with App Store Guidelines.

Modify the view to include the following requirements:

  • Restore Functionality: Add a "Restore Purchases" button that calls a restorePurchases() function.
  • Legal Links: Add two distinct buttons or links labeled "Terms of Use" and "Privacy Policy".
  • Pricing Transparency: Add a Text element that clearly states the billing terms (e.g., "Annual subscription: $29.99/year").
  • Layout: Ensure the "Buy" button remains the primary call to action, while the Restore and Legal links are placed unobtrusively at the bottom of the view using a VStack or HStack.

Note: You do not need to implement the actual network logic for the legal links or the StoreKit restore logic; simply create the UI elements and the function signatures they call.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.