Promotional and introductory offers follow store guidelines
Why it matters
Apple Promotional Offers are only valid for users who have previously subscribed to the product — presenting them to first-time users generates an invalid purchase attempt that fails at the platform level. An offer identifier string that does not match exactly what is configured in App Store Connect causes the same failure. Both scenarios result in a purchase error that the user experiences as a broken "Subscribe" button. Apple's promotional offer system requires server-side signature generation to prevent unauthorized use, so a mismatch between the code's offer identifier and App Store Connect configuration breaks the entire offer flow silently.
Severity rationale
Low because misconfigured promotional offers break the discount flow for targeted users but do not affect the primary subscription purchase path for new subscribers.
Remediation
Verify that every promotional offer identifier string in your codebase matches exactly the identifier configured in App Store Connect under Subscriptions → [Your Subscription] → Subscription Prices → Promotional Offers. Check eligibility before showing a promotional offer to a user.
// StoreKit 2 — check eligibility before showing the offer
if let promoOffer = await subscription.promotionalOffer(offerID: "win_back_50") {
// User is eligible (has a prior subscription history)
try await product.purchase(options: [.promotionalOffer(promoOffer)])
}
// If subscription.promotionalOffer returns nil, the user is not eligible
For RevenueCat promotional offers, use Purchases.purchasePackage(package, promotionalOffer: offer) and confirm the offer's identifier property matches App Store Connect before shipping. Audit all offer identifier strings in src/lib/iap/offers.ts or equivalent against your current App Store Connect configuration.
Detection
- ID:
promo-offers - Severity:
low - What to look for: Count all relevant instances and enumerate each. If the app uses promotional offers (Apple Promotional Offers — only for existing or lapsed subscribers) or introductory offers (for new subscribers), check that they are configured and applied correctly. Look for: (1)
Product.SubscriptionOfferusage in StoreKit 2, orSKPaymentDiscountin StoreKit 1 (older API). (2) RevenueCat promotional offers:Purchases.purchasePackage(package, promotionalOffer: offer). (3) Promotional offer eligibility checks — Apple Promotional Offers are only valid for users who have previously subscribed. Showing a promotional offer to a first-time subscriber is invalid. (4) Offer codes: look forredeemOfferCode()(StoreKit 2) oropenStoreProductWithParameters()calls that handle offer code redemption. (5) In promotional offer configurations: the offer identifier string in the code must match exactly what is configured in App Store Connect. Fail pattern: a promotional offer (win-back campaign) incorrectly shown to users who never subscribed, causing an invalid purchase attempt. - Pass criteria: Promotional offers are only presented to eligible users (lapsed subscribers for Apple Promotional Offers); offer identifiers in code match App Store Connect configuration; or no promotional offers are used. At least 1 implementation must be verified.
- Fail criteria: Promotional offer identifiers do not match App Store Connect; Apple Promotional Offers shown to non-subscribers; offer flow is stubbed and does not complete.
- Skip (N/A) when: No promotional or introductory offers configured.
- Detail on fail:
"Promotional offer ID 'win_back_50_off' in src/lib/iap/offers.ts does not match the offer identifier configured in App Store Connect — promotional offer purchase will fail at the platform level"or"Apple Promotional Offer shown to all users in PaywallScreen.tsx without checking prior subscription history" - Remediation: Promotional offers require careful configuration on both the code and the App Store Connect side:
- For Apple Promotional Offers, verify user eligibility before showing:
// StoreKit 2 if let promoOffer = await subscription.promotionalOffer(offerID: "win_back_50") { // User is eligible try await product.purchase(options: [.promotionalOffer(promoOffer)]) } - Offer identifiers in code must exactly match what is created in App Store Connect under Subscriptions → [Your Subscription] → Subscription Prices → Add Introductory Offer
- For Apple Promotional Offers, verify user eligibility before showing:
External references
- external · apple-promotional-offers — Apple — Implementing Promotional Offers in Your App (StoreKit Promotional Offers)
Taxons
History
- 2026-04-18·v1.0.0·Initial import from app-store-iap-subscriptions·automated