Privacy Manifests: Swift & iOS Best Practices Explained
Apple's privacy manifest requirements have become a critical part of iOS app development, especially as the App Store tightens enforcement. Privacy manifests: Swift & iOS best practices explained means declaring what data your app collects and why it accesses certain sensitive APIs—a shift from implicit permissions to explicit documentation. This article covers everything your team needs to know to implement privacy manifests correctly and avoid App Store rejections.
Understanding the PrivacyInfo.xcprivacy File
The PrivacyInfo.xcprivacy file is an XML property list that sits in your app's bundle and declares your data collection and API usage to Apple and users. It's not a new permission system—users still grant runtime permissions—but rather a transparency layer that tells Apple exactly what you're doing and why.
Every app targeting iOS 17 or later must include this file. You can create it manually or use Xcode's built-in privacy manifest editor. In Xcode, right-click your project, select New File, and choose App Privacy Report. This generates the basic XML structure:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array/>
</dict>
</plist>The file has four main sections: tracking status, tracking domains, collected data types, and accessed API types. Your team should treat this as a living document that updates whenever you add dependencies or change data collection behavior.
Declaring Collected Data Types
The NSPrivacyCollectedDataTypes section lists every category of user data your app collects, whether through direct user action, SDK integration, or backend services. Apple defines specific data types: health and fitness, financial info, location, contacts, photos and videos, audio, search history, browsing history, user ID, device ID, purchase history, and others.
For each data type, you must specify three things: the category itself, whether collection is linked to the user's identity, and whether it's used for tracking. Here's a practical example for an e-commerce app that collects purchase history and contacts:
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypePurchaseHistory</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeContacts</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>The "linked" flag means the data is connected to an identifiable user. "Tracking" means it's used to track behavior across other apps or websites. Purposes include app functionality, analytics, product improvement, app support, or third-party advertising. Be honest here—App Review will cross-reference your claims against your code and privacy policy.
Required Reason APIs Need Justification
Required Reason APIs are sensitive functions that Apple scrutinizes heavily. These include file timestamp access, system boot time, disk usage, active keyboard, clipboard access, and various device identifiers. Using any of these without an approved reason gets your app rejected.
For each required reason API your code calls, you must declare the reason in NSPrivacyAccessedAPITypes. Apple provides a curated list of approved reasons per API. For example, if you're calling NSFileModificationDate to check when a cache file was last updated for app functionality purposes, here's how it looks:
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPITypeFileTimestampAPIs</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>DDA9.1</string>
</array>
</dict>
</array>The string DDA9.1 is Apple's reason code for "To improve app functionality and user experience" when accessing file timestamps. Each reason code maps to specific purposes. For clipboard access, you might use C617.1 (pasting links or documents). Never use a reason code that doesn't match your actual use case—App Review audits these declarations.
In your Swift code, document why you're calling sensitive APIs. This isn't about adding comments everywhere, but rather ensuring that call sites are intentional and traceable:
// MARK: - Required Reason API: File timestamp access (DDA9.1)
// We check cache file modification times to determine if cached data is stale
func isCacheStale(fileURL: URL) -> Bool {
guard let attributes = try? FileManager.default.attributesOfItem(atPath: fileURL.path),
let modificationDate = attributes[.modificationDate] as? Date else {
return true
}
let cacheMaxAge: TimeInterval = 3600 // 1 hour
return Date().timeIntervalSince(modificationDate) > cacheMaxAge
}If you're using a required reason API indirectly through a framework, your framework's privacy manifest handles the declaration. However, you're still responsible for understanding what your dependencies do.
Third-Party SDKs Need Manifests Too
This is where many teams stumble. If you integrate an analytics SDK, advertising SDK, or payment gateway, that library might use required reason APIs or collect data. Starting with Xcode 15.1, you can include privacy manifests in third-party packages and frameworks. Apple expects SDK developers to provide them, but not all have caught up yet.
When evaluating third-party libraries, check their privacy manifest. Many popular SDKs now include one in their bundle. You can inspect it by extracting the framework and looking for PrivacyInfo.xcprivacy. If a library doesn't have one and uses sensitive APIs, you have three options:
- Contact the SDK maintainer and request a privacy manifest
- Create and maintain your own privacy manifest for that library (only possible if you have source access)
- Stop using the library if it can't provide transparency
In real-world scenarios, we've seen teams integrate Firebase, Mixpanel, and AdMob SDKs. Google provides privacy manifests for all three. However, smaller or legacy SDKs may not, and your app's submission will be held up until every dependency declares its data usage.
To check which dependencies have privacy manifests, use Xcode's Privacy Report feature. In Xcode 15+, go to Product > Build > Privacy Report. This generates a summary of all declared APIs and data types across your entire dependency tree, plus highlights missing manifests:
| SDK | Has Manifest | Collected Data | Required APIs |
|---|---|---|---|
| Firebase | Yes | User ID, Analytics | System uptime |
| CustomAnalytics | No | Unknown | Unknown |
| PaymentKit | Yes | Purchase history | None |
If you maintain a framework that your team distributes, you should add a privacy manifest to its target. Create the file in Xcode and ensure it's included in the framework's public headers. SPM packages can include it directly in the root directory.
Common Mistakes
Over-declaring data collection: Some teams declare that they collect "user ID" when they only use a device-scoped identifier. This triggers additional scrutiny. Be specific about what you actually collect and use.
Mismatching reason codes: Declaring C617.1 (clipboard access for pasting content) when you're using the clipboard to track user behavior is a rejection reason. Map reason codes carefully to your actual implementation.
Ignoring transitive dependencies: Your app depends on Library A, which depends on Library B. If Library B uses required reason APIs and lacks a manifest, your app fails. Audit your entire dependency graph, not just direct imports.
Forgetting to update manifests: After adding a new analytics or payment SDK, teams often forget to update the privacy manifest. Automate this step by reviewing the manifest as part of dependency updates in your CI/CD pipeline.
Claiming "tracking" falsely: The NSPrivacyCollectedDataTypeTracking flag means cross-app or cross-site tracking. Collecting analytics within your app only isn't tracking. If you mark this as true when it's false, you signal unnecessary data sharing and create compliance risk.
Key Takeaways
- Every app targeting iOS 17+ must include a
PrivacyInfo.xcprivacyfile that declares collected data types and required reason API usage. - Be specific and honest when declaring data categories, linking status, and purposes. App Review cross-references your manifest against your code and privacy policy.
- Required reason APIs require mapped reason codes. Use Apple's official list and ensure the reason matches your actual implementation.
- Third-party SDKs must provide their own privacy manifests. Audit all dependencies and escalate with SDK maintainers if manifests are missing.
- Use Xcode's Privacy Report feature to get a full view of declared data and APIs across your app and all dependencies.
- Treat the privacy manifest as living documentation. Update it whenever you add dependencies, change data collection, or modify API usage.
- Document required reason API calls in your code to maintain clarity for code reviews and future audits.






Comments
Loading comments…