App Store Review Guideline 2.1 (Performance - App Completeness): Fix Subscription Page Infinite Loading (Receipt Validation and Frontend Timeout)
App Store Review Guideline 2.1 (Performance - App Completeness): Fix Subscription Page Infinite Loading (Receipt Validation and Frontend Timeout)
A common rejection reason: subscription page spins forever due to improper receipt validation and missing frontend timeouts.
1. Issue Context (Guideline 2.1)
- Symptom: loading never ends; poor UX.
- Causes:
- Backend only calls production endpoint; sandbox receipts not handled (must handle 21007).
- Frontend requests have no timeout or error UI, leading to infinite waiting.
2. Solution Overview
- Backend: production-first receipt validation with sandbox fallback; enforce timeouts.
- Frontend: set request timeouts; show loading state; surface errors; allow retry.
- Platform: ensure paid apps agreement is accepted in App Store Connect.
3. Backend: Receipt Validation (Python/Requests)
import requests
APPLE_PRODUCTION_URL = "https://buy.itunes.apple.com/verifyReceipt"
APPLE_SANDBOX_URL = "https://sandbox.itunes.apple.com/verifyReceipt"
TIMEOUT_SECONDS = 10
def validate_receipt(receipt_data: str, password: str) -> dict:
"""Try production first; if status == 21007 then retry sandbox. Apply request timeouts."""
payload = {
"receipt-data": receipt_data,
"password": password,
"exclude-old-transactions": True,
}
# 1) production first
resp = requests.post(APPLE_PRODUCTION_URL, json=payload, timeout=TIMEOUT_SECONDS)
result = resp.json()
# 2) sandbox fallback
if result.get("status") == 21007:
resp = requests.post(APPLE_SANDBOX_URL, json=payload, timeout=TIMEOUT_SECONDS)
result = resp.json()
return result
Key points: