iOS App Store Compliance Checklist
A step-by-step guide to ensure your iOS app with PushEngage push notifications passes Apple's App Store review. Also covers migration from OneSignal and Firebase Cloud Messaging.
Applies to: PushEngage iOS SDK v0.0.6+ | iOS 10.0+
| Integration Method | Minimum Swift | Minimum Xcode |
|---|---|---|
| CocoaPods | 5.0 | 11+ |
| Swift Package Manager | 5.9 | 15+ |
How to Use This Checklist
Work through each section in order as you integrate PushEngage and prepare for App Store submission. Each item includes a Verify step so you can confirm completion.
Legend:
- Required — your app will be rejected without this
- Recommended — not strictly required but significantly reduces rejection risk
- Migration — only needed if switching from another push service
Phase 1: Pre-Integration Setup
APNs Certificate (.p12) — Required
Apple Push Notification service requires authentication to send push notifications to your app. The PushEngage dashboard accepts APNs .p12 certificates.
.p12 certificates expire annually. Set a calendar reminder 2–4 weeks before expiry to renew — push delivery will silently stop once a certificate expires. Use the "Sandbox & Production" certificate type to cover both development and App Store builds with a single certificate.
Create an APNs certificate in the Apple Developer Portal
- Go to Certificates, Identifiers & Profiles → Certificates
- Click "+" and select Apple Push Notification service SSL (Sandbox & Production)
- Complete the CSR flow via Keychain Access:
- Open Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority
- Enter your email, leave CA Email Address empty, select Saved to disk
- Upload the generated
.certSigningRequestfile to the Apple Developer Portal
- Download the generated
.cerfile, double-click to install in Keychain Access - Open Keychain Access → My Certificates → find "Apple Push Services: com.yourapp.bundleid"
- Right-click → Export →
.p12format, set an export password - Verify: You have a
.p12file and know the export password
Upload the .p12 certificate to the PushEngage Dashboard
- Go to Site Settings → Installation → iOS SDK
- Fill in the following fields:
- App Push Id — your app's bundle identifier (e.g.,
com.yourcompany.yourapp) - Certificate (.p12) — upload the
.p12file exported from Keychain Access - Private Key Password — the export password set during the
.p12export
- App Push Id — your app's bundle identifier (e.g.,
- Click Update
- Verify: PushEngage Dashboard shows the certificate is configured for iOS push
App ID Configuration — Required
Enable Push Notifications for your App ID
- Go to Certificates, Identifiers & Profiles → Identifiers
- Select your App ID → under Capabilities, enable Push Notifications
- Verify: Push Notifications shows a green checkmark next to your App ID
Create or update your Provisioning Profile
- After enabling Push Notifications on your App ID, regenerate your provisioning profile
- Download and install the new profile in Xcode
- Verify: Xcode → Signing & Capabilities shows no provisioning profile errors
Phase 2: Xcode Project Configuration
Capabilities & Entitlements — Required
Add Push Notifications capability
- Xcode → your target → Signing & Capabilities → + Capability → Push Notifications
- This adds the
aps-environmententitlement to your app - Verify: Your
.entitlementsfile contains:(Xcode sets this to<key>aps-environment</key>
<string>development</string>productionautomatically for App Store/TestFlight builds.)
Add Background Modes capability with Remote notifications
- Xcode → your target → Signing & Capabilities → + Capability → Background Modes
- Check Remote notifications and Background fetch
- Verify: Your
Info.plistcontains:<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
Add App Groups capability — Required for SDK to function
- The PushEngage SDK uses an App Group-backed
UserDefaultssuite for all internal state (device token, subscriber data, permission status). Without this, the SDK silently loses all stored state between app launches. - Xcode → your target → Signing & Capabilities → + Capability → App Groups
- Create a group identifier, e.g.,
group.com.yourcompany.yourapp - Add the same App Group to your main app target, Notification Service Extension, and any other extensions
- Add
PushEngage_App_Group_Keyto each target'sInfo.plistwith the same group identifier - Verify: All targets list the same App Group in their
.entitlementsfiles:<key>com.apple.security.application-groups</key>
<array>
<string>group.com.yourcompany.yourapp</string>
</array> - Verify: Each
Info.plistcontains:<key>PushEngage_App_Group_Key</key>
<string>group.com.yourcompany.yourapp</string>
- The PushEngage SDK uses an App Group-backed
Notification Service Extension — Required for Rich Notifications & Delivery Tracking
The Notification Service Extension is required for rich notifications (images, action buttons), accurate delivery tracking, and badge management. Without it, the SDK can only deliver basic text notifications.
Create a Notification Service Extension target
- Xcode → File → New → Target → Notification Service Extension
- Name it (e.g.,
PushEngageNotificationServiceExtension) - Set the same deployment target as your main app (iOS 10.0+)
- Add the PushEngage SDK as a dependency to this target
- Verify: Your project has a separate Notification Service Extension target
Add App Groups to the extension
- Use the same App Group identifier as your main app
- Add
PushEngage_App_Group_Keyto the extension'sInfo.plist - Verify: Extension's
.entitlementsfile contains the matching App Group
Notification Content Extension — Optional
The Notification Content Extension allows custom notification UI. Only add this if you need custom notification layouts.
Create a Notification Content Extension target (if needed)
- Xcode → File → New → Target → Notification Content Extension
- Configure
UNNotificationExtensionCategoryin the extension'sInfo.plist - Verify: Extension responds to the correct notification category
Add App Groups to the Content Extension
- Use the same App Group identifier as your main app and Service Extension
- Add
PushEngage_App_Group_Keyto the Content Extension'sInfo.plist - Verify: Content Extension's
.entitlementsfile contains the matching App Group
Phase 3: Privacy & Data Compliance
Privacy Manifest (PrivacyInfo.xcprivacy) — Recommended
Apple maintains a specific list of third-party SDKs required to include privacy manifests and code signatures. PushEngage is not currently on this list, so Apple will not reject your app solely because the SDK lacks a bundled privacy manifest. However, your app must still declare its own data collection and Required Reason API usage — which includes APIs called by PushEngage.
Create your app's privacy manifest (if not already present)
- Xcode → File → New → File → App Privacy → Privacy Manifest
- Declare data collection that PushEngage performs (see table below)
- Declare Required Reason APIs used by PushEngage (see section below)
- Verify:
PrivacyInfo.xcprivacyexists in your app bundle
Check for ITMS-91053 warnings during upload
- These are informational, not blocking, since PushEngage is not on Apple's required list
- Address them by adding the appropriate declarations to your app's privacy manifest
Data Collected by PushEngage iOS SDK
| Data Type | Purpose | Linked to User | Tracking |
|---|---|---|---|
| Device ID (APNs token) | Push notification delivery | No | No |
| Device model | Analytics & delivery optimization | No | No |
| Device manufacturer | Analytics (hardcoded "Apple") | No | No |
| Device type (phone/tablet) | Analytics & delivery optimization | No | No |
| User agent string | Analytics (derived from device model, e.g. "Apple iPhone14,2") | No | No |
| OS version | Compatibility & analytics | No | No |
| Timezone | Scheduled notification delivery | No | No |
| Language / locale | Notification localization | No | No |
| Screen dimensions | Notification display optimization | No | No |
| App bundle identifier | App identification | No | No |
| Notification permission state | Subscription management | No | No |
| APNs environment (dev/prod) | Delivery routing | No | No |
IP address: The SDK does not collect or send IP addresses from the device. PushEngage's backend servers receive the device's IP address as part of standard HTTP communication. Disclose this in your App Store privacy nutrition labels if your privacy policy covers server-side data.
Location: The SDK does not request GPS/location data or use CoreLocation. It only checks whether your app has declared location usage description keys in Info.plist and reports this as a boolean flag.
IDFA: The SDK does not collect IDFA, does not require App Tracking Transparency, and does not track users across apps.
Required Reason APIs
The PushEngage SDK uses the following API from Apple's "Required Reason" list:
- Declare
NSPrivacyAccessedAPITypesin your app's privacy manifestUserDefaults(NSUserDefaults) — Reason:CA92.1(App Functionality: app-specific data storage)- No other Required Reason APIs are used by the SDK
- Verify: No ITMS-91053 warnings when uploading to App Store Connect
App Privacy "Nutrition Labels" — Required
When you submit your app to App Store Connect, you must disclose what data your app collects — including data collected by third-party SDKs.
- Complete the App Privacy section in App Store Connect
- App Store Connect → Your App → App Privacy
- Declare the data types listed in the table above
- For each data type, specify: collected, purpose, linked to user identity, used for tracking
- Verify: App Store Connect shows your privacy disclosures with no warnings
Recommended Disclosures for PushEngage
| App Store Connect Category | Disclose? | Details |
|---|---|---|
| Do you or your third-party partners collect data from this app? | Yes | |
| Identifiers → Device ID | Yes | App Functionality (push delivery). Not linked to user identity unless your app links it via addProfileId. Not used for tracking. |
| Usage Data → Product Interaction | Yes | SDK tracks notification views and clicks for delivery analytics. Not linked to user identity. Not used for tracking. |
| Diagnostics (crash data, performance) | No | SDK does not collect crash reports or performance diagnostics. |
App Tracking Transparency (ATT) — Not Required for PushEngage
- Confirm ATT is NOT required for PushEngage
- PushEngage does not use IDFA or track users across apps
- You do not need to add
NSUserTrackingUsageDescriptionto yourInfo.plistfor PushEngage - Verify: Search your PushEngage integration code for
ATTrackingManager— it should not be present - Note: If other SDKs in your app use IDFA, you still need ATT for those
Phase 4: App Store Review Guidelines Compliance
Apple's review guidelines have specific rules about push notifications. Violating these is one of the most common causes of rejection.
Content & Behavior Rules — Required
Do NOT require push notifications to use the app (Guidelines 4.5.4, 5.1.2)
- Apps cannot require users to enable push notifications to access features or receive compensation
- Do not gate content, features, or rewards behind push notification opt-in
- Verify: Test your app with notifications denied — all features should work
Keep notification content relevant to the app (Guideline 2.5.16)
- Notifications must relate to your app's core content and functionality
- Do not send notifications unrelated to what the user signed up for
- Verify: Review your notification campaigns in PushEngage Dashboard — all should relate to app content
No advertising in push notifications without explicit opt-in (Guideline 4.5.4)
- Push notifications must not be used for promotions or direct marketing unless users have explicitly opted in via consent language in your app
- You must provide a method to opt out of such messages
- Promotional content for your own app features is generally acceptable if the user opted in
- Verify: Review notification templates — none should contain unsolicited promotional content
No spam or unsolicited notifications (Guideline 4.5.4)
- Send notifications at reasonable frequency; content should provide value
- Do not use push as a re-engagement mechanism for inactive users without consent
- Verify: Check notification frequency in PushEngage analytics — avoid more than 2–3 per day unless user-triggered
Provide notification preferences — Recommended
- Include an in-app setting for users to manage notification types or frequency
- Reviewers look favorably on this even though it's not strictly required
- Verify: Your app has a Settings screen with notification preferences
Permission Request Best Practices — Recommended
Request notification permission at an appropriate time
- Do NOT request permission immediately on first launch
- Show a pre-permission screen explaining the value of notifications before the system prompt
- Request permission after the user has experienced your app's core value
- Verify: Test a fresh install — the system permission prompt should not appear on the first screen
Handle permission denial gracefully
- If the user denies, do not repeatedly prompt
- Provide a path to enable notifications later via Settings
- Verify: Deny permissions and use the app — no repeated prompts or degraded experience
Phase 5: Migration Compliance
Skip this section if this is a fresh integration without a previous push notification service.
Migrating from OneSignal — Migration
OneSignal is on Apple's required third-party SDK list. Removing it removes its privacy manifest and code signature requirements from your app.
Remove OneSignal SDK completely
- Remove from Podfile / Package.swift
- Delete all OneSignal import statements and API calls
- Remove OneSignal's Notification Service Extension (if separate from yours)
- Verify:
grep -r "OneSignal" --include="*.swift" --include="*.m" --include="*.h" .
# Should return no results
Remove OneSignal's privacy manifest entries
- Remove any OneSignal-specific entries from your privacy manifest
- Add PushEngage's data collection declarations (see Phase 3)
- Verify: Your
PrivacyInfo.xcprivacyno longer references OneSignal data types
Update App Privacy nutrition labels
- OneSignal and PushEngage collect similar but not identical data
- Review your App Store Connect privacy disclosures and update accordingly
- Verify: App Store Connect privacy section reflects PushEngage's data collection
Upload your APNs credential to PushEngage
- Your existing APNs
.p12certificate works with PushEngage — no change needed to the certificate itself - Go to Site Settings → Installation → iOS SDK and upload the same
.p12certificate you used with OneSignal - Verify: Test push notification delivered successfully via PushEngage
- Your existing APNs
Map subscriber data
- OneSignal Player IDs do not transfer to PushEngage
- Device tokens are re-registered automatically when the PushEngage SDK initializes
- If you stored OneSignal Player IDs in your backend, plan for the subscriber migration
- Verify: New subscribers appear in PushEngage Dashboard after SDK switch
Migrating from Firebase Cloud Messaging (FCM) — Migration
FirebaseMessaging is on Apple's required third-party SDK list. If you remove it but keep other Firebase SDKs (e.g., FirebaseCore, FirebaseCrashlytics), those still require their own privacy manifests.
Keep Firebase dependencies if using other Firebase services
- PushEngage uses APNs directly, not FCM
- If you use Firebase for Analytics, Crashlytics, etc., keep those dependencies
- Remove only FCM-specific notification handling code
- Verify: Other Firebase services still work after removing FCM notification code
Remove FCM notification handling code
- Remove
FIRMessagingdelegate methods andFIRMessagingDelegateconformance - Remove the
messaging:didReceiveRegistrationToken:handler - Keep Firebase initialization if using other Firebase services
- Verify:
grep -r "FIRMessaging\|FirebaseMessaging" --include="*.swift" --include="*.m" .
# Should return no notification-specific results
- Remove
Update privacy manifest for FCM removal
- If FCM had entries in your privacy manifest, remove them
- Firebase Analytics (if kept) has its own privacy manifest — ensure it's still included
- Verify: Build succeeds with no ITMS-91053 warnings
Upload your APNs credential to PushEngage
- FCM wraps APNs internally; PushEngage connects to APNs directly
- Go to Site Settings → Installation → iOS SDK and upload a
.p12certificate (see Phase 1 if you need to create one) - Verify: Test push delivered via PushEngage (not through FCM relay)
Handle dual-SDK transition period (if migrating gradually)
- If running both services temporarily, ensure only one service handles each notification
- Use notification categories or payload keys to distinguish
- Verify: No duplicate notifications received during transition
Phase 6: Pre-Submission Final Checklist
Run through this section before every App Store submission.
Entitlements & Capabilities
- Push Notifications capability enabled in Xcode
- Background Modes → Remote notifications enabled
- App Groups configured with
PushEngage_App_Group_KeyinInfo.plistfor all targets -
aps-environmentset toproductionfor App Store builds (Xcode sets this automatically) - Provisioning profile is current and includes Push Notifications
Verify the aps-environment entitlement in your built app:
codesign -d --entitlements :- /path/to/YourApp.app 2>&1 | grep aps-environment
# Should show: <string>production</string>
Privacy
-
PrivacyInfo.xcprivacyexists in your app bundle with PushEngage data declarations -
UserDefaultsdeclared as Required Reason API with reasonCA92.1 - App Privacy nutrition labels completed in App Store Connect
- No ITMS-91053 or ITMS-91061 warnings in Xcode or Transporter
Notifications
- Test push notification received on a physical device (Simulator cannot receive push notifications)
- Rich notifications display correctly (images, action buttons) — requires Notification Service Extension
- Deep links from notifications navigate to the correct screens
- Notification permission denial does not break any app functionality
- No notification-gated content or forced opt-ins
- Notification content is relevant to app functionality
Code Cleanup
- No previous SDK references (OneSignal / FCM) remain in code
- No debug APNs configuration in production build
- PushEngage logging disabled for production:
PushEngage.enableLogging = false - No hardcoded test device tokens in code
Build & Archive
- Archive build succeeds with no signing errors
- Transporter / Xcode upload shows no new warnings
- TestFlight build receives push notifications correctly
Common App Store Rejection Reasons
| Rejection Reason | Guideline | How to Avoid |
|---|---|---|
| App requires push notifications to function | 4.5.4, 5.1.2 | Ensure all features work without notifications enabled |
| Notifications used for unsolicited marketing | 4.5.4 | Only send promotions if user explicitly opted in; provide opt-out |
| Notifications unrelated to app content | 2.5.16 | Keep notification content related to your app's functionality |
| Excessive or irrelevant notifications | 4.5.4 | Limit frequency; keep content relevant to app |
| Missing privacy disclosures for push data | 5.1.1 | Complete App Privacy section and privacy manifest |
| Invalid provisioning profile | N/A | Regenerate profile after enabling Push Notifications capability |
| Missing push entitlement | N/A | Add Push Notifications capability in Xcode |
| Privacy manifest warnings | N/A | Include PrivacyInfo.xcprivacy with required declarations |
iOS Version Considerations
| Requirement | iOS 10–11 | iOS 12+ | iOS 17+ | iOS 18+ |
|---|---|---|---|---|
| Push Notifications capability | Required | Required | Required | Required |
| Background Modes | Required | Required | Required | Required |
| App-level Privacy Manifest | Required for all App Store submissions since May 2024 | |||
| Provisional Notifications | N/A | Available | Available | Available |
| Notification Categories | Available | Available | Available | Available |
| Priority Notifications | N/A | N/A | N/A | Available |
iOS 12 introduced provisional (quiet) notifications that require no user permission prompt. PushEngage SDK v0.0.6 does not request provisional authorization — it requests .alert, .badge, and .sound only. If you need provisional delivery, you would need to request it separately via UNUserNotificationCenter before calling PushEngage initialization.
The privacy manifest is an App Store Connect submission requirement, not an iOS runtime feature. You need it in your app bundle regardless of which iOS version you target.
Useful Commands & Verification Tools
Check entitlements in your built app:
codesign -d --entitlements :- /path/to/YourApp.app
Search for old SDK references:
# Search for OneSignal
grep -r "OneSignal" --include="*.swift" --include="*.m" --include="*.h" \
--include="*.plist" --include="*.pbxproj" .
# Search for Firebase Messaging
grep -r "FIRMessaging\|FirebaseMessaging" --include="*.swift" --include="*.m" \
--include="*.plist" --include="*.pbxproj" .
Verify privacy manifest in built app:
find /path/to/YourApp.app -name "PrivacyInfo.xcprivacy"
Check .p12 certificate expiry date:
# View certificate details including expiry date
openssl pkcs12 -in YourCert.p12 -nokeys | openssl x509 -noout -dates
# Look for "notAfter" — that is your expiry date
Test APNs connectivity with your .p12 certificate:
# Step 1: Convert .p12 to .pem (enter your export password when prompted)
openssl pkcs12 -in YourCert.p12 -out apns-cert.pem -nodes
# If you see an "unsupported" or "Mac verify error" with OpenSSL 3 (e.g. Homebrew),
# retry with the legacy provider:
# openssl pkcs12 -legacy -in YourCert.p12 -out apns-cert.pem -nodes
# Step 2: Get your device token from Xcode console when your app registers
# Step 3: Send a test push
curl -v --cert apns-cert.pem \
--header "apns-topic: com.yourapp.bundleid" \
--header "apns-push-type: alert" \
--data '{"aps":{"alert":"Test from curl","sound":"default"}}' \
--http2 https://api.push.apple.com/3/device/YOUR_DEVICE_TOKEN
# For sandbox/development testing use:
# https://api.sandbox.push.apple.com/3/device/YOUR_DEVICE_TOKEN