WWDC Quick Look 💓 By SwiftGGTeam
What's new in Apple In-App Purchase

What's new in Apple In-App Purchase

Watch original video

Highlight

Apple adds monthly payment plans with a 12-month commitment for annual subscriptions. Users pay monthly, lowering the decision barrier, while developers secure long-term subscription revenue. StoreKit adds PricingTerms and billingPlanType APIs for display and purchase, server-side JWSTransaction adds a commitmentInfo field to track fulfillment progress, and App Store Connect now supports bundling IAPs with other review items in a single review submission flow.

Core Content

The pricing dilemma for annual subscriptions

Every developer running a subscription business has faced this problem: push annual subscriptions and users abandon when they see the full upfront charge; push monthly subscriptions and users can cancel at any time, making LTV hard to protect. Both options have tradeoffs, but there has been no middle ground.

Apple provides an official solution in iOS 26.5: monthly subscriptions with a 12-month commitment. Users pay a smaller amount each month, but the contract is locked for 12 months. Developers get a predictable long-term revenue expectation, while users face a lower decision barrier.

This plan is configured directly in App Store Connect. Select a one-year auto-renewable subscription, set availability under “monthly with a 12-month commitment availability,” and follow the steps to finish configuration. Each billing plan can configure subscription offers independently, such as offering a free trial only to commitment-plan users.

(01:53)

Showing the new billing plan with StoreKit

After configuration, StoreKit exposes billing plan information through the new PricingTerms property. SubscriptionInfo.pricingTerms returns an array containing every available billing plan for the product. The default annual prepaid plan type is .upFront; if monthly commitment is configured, the array includes an additional .monthly object.

When using SubscriptionStoreView in SwiftUI, you can filter and prioritize the monthly commitment plan with the .preferredSubscriptionPricingTerms modifier.

(03:29)

Tracking commitment progress on the server

After a user subscribes, the server needs to know which month of the commitment period the user is in and how many periods remain. JWSTransaction and JWSRenewalInfo add a commitmentInfo field with data such as billingPeriodNumber for the current period, totalBillingPeriods for the total number of periods, and commitmentExpiresDate for the commitment end date.

Key point: if billingPeriodNumber is less than totalBillingPeriods, the user is still within the commitment period. Even if the user turns off auto-renewal in system settings, Apple will continue monthly billing until the commitment period ends. The server must not remove user entitlement early.

(07:45)

Offer Code Redemption API upgrade

The offer code redemption API now returns VerificationResult. On success, you directly receive the transaction object; on failure, you receive a specific error. There is no longer any need to depend on Transaction.updates and guess the redemption result.

Use the .offerCodeRedemption modifier in SwiftUI and presentOfferCodeRedeemSheet in UIKit. StoreKit Testing in Xcode 27 supports testing the new redemption API.

(09:58)

Unified App Store Connect review submission flow

IAP review submissions can now be packaged into one Submission with other review items, such as In-App Events, custom product pages, and product page optimizations. After submission, you can view the status of every review item in a centralized view.

The reviewSubmissions endpoint in the App Store Connect API expands support for IAP, subscription, and subscription group resources. The old IAP-specific submission APIs will be deprecated, and Apple recommends migrating to the new reviewSubmission and reviewSubmissionItems resources.

(10:42)

Details

Displaying a monthly commitment plan in StoreKit views

(03:29)

import StoreKit
import SwiftUI

struct SubscriptionStore: View {
    var body: some View {
        SubscriptionStoreView(groupID: "3F19ED53") {
            // Custom marketing content
        }
        .preferredSubscriptionPricingTerms { _, subscriptionInfo in
            subscriptionInfo.pricingTerms.first {
                $0.billingPlanType == .monthly
            }
        }
    }
}

Key points:

  • SubscriptionStoreView automatically loads product metadata from the App Store and adapts its layout across platforms
  • .preferredSubscriptionPricingTerms is a modifier added in iOS 26.5 for filtering the billing plan to display first
  • subscriptionInfo.pricingTerms returns all available billing plans. .upFront is always present, while .monthly appears only when a commitment plan is configured
  • Without filtering, the system defaults to .upFront, so the lower monthly price advantage of monthly commitment is not visible

Getting pricing information and purchasing in a custom store UI

(04:02)

import StoreKit

var product: Product?
// Fetch and assign product

let pricingTerms = product?.subscription?.pricingTerms
    .first(where: { $0.billingPlanType == .monthly })

if let pricingTerms {
    let monthlyPrice = pricingTerms.billingDisplayPrice
    let totalCommitmentPrice = pricingTerms.commitmentInfo.price
    // Display both monthly and total commitment price to the customer
}

let result = try? await product?.purchase(options: [.billingPlanType(.monthly)])
switch result {
    // Verify the transaction, give the customer access to
    // the purchased content, and then finish the transaction
}

Key points:

  • billingDisplayPrice is the monthly installment amount displayed to the user
  • commitmentInfo.price is the total price across the 12 months; the UI should show both the monthly payment and total price
  • Pass the .billingPlanType(.monthly) option when purchasing to specify the monthly commitment plan
  • Billing plan metadata is returned only when the plan is available in the user’s storefront

Manage Subscriptions sheet

(05:05)

import SwiftUI
import StoreKit

struct ManageSubscriptionsButton: View {
    let subscriptionGroupID: String
    @State var presentingManageSubscriptionsSheet: Bool = false

    var body: some View {
        Button("Manage Subscriptions") {
            presentingManageSubscriptionsSheet = true
        }
        .manageSubscriptionsSheet(
            isPresented: $presentingManageSubscriptionsSheet,
            subscriptionGroupID: subscriptionGroupID
        )
    }
}

Key points:

  • .manageSubscriptionsSheet is the SwiftUI way to show the subscription management interface
  • The UIKit equivalent is the showManageSubscriptions API
  • Users can view remaining payment periods and the commitment renewal date in the management interface
  • The App Store automatically provides the new management UI for commitment subscriptions

Commitment information in server-side JWSTransaction

(07:45)

{
    "expiresDate": 1783503660000,
    "price": 10990,
    "productId": "plus.pro.annual",
    "purchaseDate": 1780911660000,
    "type": "Auto-Renewable Subscription",
    "billingPlanType": "MONTHLY",
    "commitmentInfo": {
        "billingPeriodNumber": 1,
        "totalBillingPeriods": 12,
        "commitmentExpiresDate": 1812447660000,
        "commitmentPrice": 131880
    }
}

Key points:

  • billingPlanType set to "MONTHLY" indicates this is a monthly commitment subscription
  • commitmentInfo.billingPeriodNumber indicates the current billing cycle number
  • commitmentInfo.totalBillingPeriods is fixed at 12
  • commitmentInfo.commitmentExpiresDate is the end time of the full commitment period
  • For .upFront transactions, commitmentInfo is nil

Commitment renewal information in server-side JWSRenewalInfo

(07:59)

{
    "renewalBillingPlanType": "MONTHLY",
    "commitmentInfo": {
        "commitmentAutoRenewProductId": "plus.standard.annual",
        "commitmentAutoRenewStatus": 0,
        "commitmentRenewalDate": 1812447660000,
        "commitmentRenewalPrice": 10990,
        "commitmentRenewalBillingPlanType": "BILLED_UPFRONT"
    }
}

Key points:

  • commitmentAutoRenewStatus set to 0 means the user has chosen not to renew after the commitment period ends
  • commitmentRenewalBillingPlanType indicates the renewal plan type after the commitment period
  • In this example, the user chose to switch to an upfront annual subscription after the commitment period
  • commitmentInfo appears in renewal info only while the current subscription is in a commitment period

Offer Code Redemption sheet

(09:58)

struct OfferCodeRedemption: View {
    @State var presentingOfferCodeSheet: Bool = false

    var body: some View {
        Button("Redeem Offer Code") {
            presentingOfferCodeSheet = true
        }
        .offerCodeRedemption(options: [], isPresented: $presentingOfferCodeSheet) { result in
            switch result {
            case .success(let verificationResult):
                switch verificationResult {
                    // Verify the transaction, give the customer access to
                    // the purchased content, and then finish the transaction
                }
            case .failure(let error):
                // Handle error
            }
        }
    }
}

Key points:

  • .offerCodeRedemption now returns VerificationResult, making redemption results explicitly trackable
  • The options parameter accepts an array of RedeemOption values for configuring redemption behavior
  • On successful redemption, verificationResult contains the transaction object
  • Use presentOfferCodeRedeemSheet in UIKit to implement the same functionality

Key Takeaways

Add monthly commitment plans to subscription products

What to do: Configure a 12-month commitment monthly payment option for existing annual subscription products, and prioritize it in the app.

Why it is worth doing: It lowers the first-payment barrier while locking in 12 months of subscription revenue. For price-sensitive users, a monthly installment amount is easier to accept than the annual total.

How to start: Find the existing one-year auto-renewable subscription in App Store Connect and set “monthly with a 12-month commitment” availability. In code, use .preferredSubscriptionPricingTerms to filter the .monthly plan and display it first.

Build commitment progress UI

What to do: In the app’s account or subscription management page, show which month of the commitment period the user is in and how many periods remain.

Why it is worth doing: Transparency increases user trust and reduces support complaints like “I didn’t know I signed up for 12 months.” It can also help users make renewal decisions before the commitment period ends.

How to start: Get the latest transaction from Transaction.currentEntitlements, read the commitmentInfo field, and calculate progress from billingPeriodNumber and totalBillingPeriods.

Upgrade offer code redemption logic

What to do: Migrate existing offer code redemption call sites to the new API and get explicit redemption result callbacks.

Why it is worth doing: The old API did not provide a direct result after redemption, requiring asynchronous listening through Transaction.updates, which was complex and error-prone. The new API returns success or failure directly.

How to start: Search for presentOfferCodeRedeemSheet calls in your code and replace them with the new version that includes a VerificationResult callback. Test the redemption flow in StoreKit Testing in Xcode 27.

Unify the review submission workflow

What to do: Move IAP review submissions into the unified reviewSubmissions workflow and package them together with the app binary and In-App Events.

Why it is worth doing: It avoids the awkward situation where the app is live but the IAP is still under review. A unified submission means all review items pass or are rejected together, with fully synchronized status.

How to start: Check existing CI/CD scripts and migrate old IAP-specific submission API calls to the reviewSubmissions and reviewSubmissionItems resources.

Prepare subscription Bundles and Suites

What to do: If you have multiple apps or multiple subscription products, plan the product structure for subscription Bundles or Suites ahead of time.

Why it is worth doing: A Bundle packages multiple separately purchasable subscriptions at a discounted price, while a Suite provides a subscription group that exists only as a whole for a set of related apps. Both can increase subscription revenue.

How to start: Test the Bundles and Suites APIs in Xcode 27, and watch for the commercialization details Apple will announce in the second half of the year.

Comments

GitHub Issues · utterances