Privacy Manifest Validation: The Complete iOS Guide
6 Apr 2026 · 10 min read · Erik van Kammen
Since May 2024, Apple requires every iOS app and third-party SDK to ship a PrivacyInfo.xcprivacy file, a structured property list that declares exactly which privacy-sensitive APIs your code touches and why. Miss one declaration and your App Store submission gets rejected. This guide walks you through the file structure, every required reason API category, how to audit your own app, and the most common mistakes that trip up even experienced teams.
A privacy manifest is a file named PrivacyInfo.xcprivacy that lives inside your app bundle (or inside each third-party SDK). It is a standard Apple property list (plist) that answers four questions:
Apple introduced privacy manifests at WWDC 2023 (session "Get started with privacy manifests") and began enforcing them for all App Store submissions on May 1, 2024. The motivation is straightforward: Apple wants machine-readable, auditable declarations of privacy behavior, not just the honor-system nutrition labels developers fill in manually on App Store Connect.
When you archive your app in Xcode, it automatically aggregates the privacy manifests from your app target and every bundled SDK into a single Privacy Report. That report feeds into your App Store privacy nutrition label and is what Apple's automated review checks against your binary.
If the report is missing entries, incomplete, or contradicts what your binary actually does, you get a warning email starting with ITMS-91053 or ITMS-91055. The email is the early warning; the block comes when you submit that build for review.
The file is a standard XML plist with four top-level keys. Here is a complete, annotated example:
<?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>
<!-- 1. Does this app/SDK track users? -->
<key>NSPrivacyTracking</key>
<false/>
<!-- 2. Domains used for tracking (only if NSPrivacyTracking is true) -->
<key>NSPrivacyTrackingDomains</key>
<array/>
<!-- 3. Required reason APIs this code accesses -->
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
<!-- 4. Types of data this app/SDK collects -->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeUserID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
</dict>
</plist>
How to create this file in Xcode: Go to File > New > File, search for "App Privacy," select the privacy manifest template, and add it to your app target. Xcode gives you a visual editor, but understanding the raw XML matters when debugging CI pipelines or reviewing SDK manifests.
Apple designates certain system APIs as "required reason APIs" because they can be used for fingerprinting (identifying a device without the user's consent). If your code calls any of these APIs, you must declare why using one of Apple's pre-approved reason codes.
There are five categories:
NSPrivacyAccessedAPICategoryFileTimestamp)APIs like NSFileCreationDate, NSFileModificationDate, and NSURLContentModificationDateKey. Common reason codes:
| Code | When to use it |
|---|---|
| C617.1 | Accessing timestamps of files inside your own app container, app group container, or CloudKit container |
| DDA9.1 | Displaying file timestamps to the user (information cannot be sent off-device) |
| 3B52.1 | Accessing timestamps for files the user explicitly selected (e.g., via a document picker) |
| 0A2A.1 | Third-party SDK wrapper that only accesses timestamps when the host app calls your API |
NSPrivacyAccessedAPICategorySystemBootTime)APIs like systemUptime and mach_absolute_time. Reason codes:
| Code | When to use it |
|---|---|
| 35F9.1 | Measuring elapsed time between events within the app, or enabling timers. Derived timing data may be sent off-device, but raw boot time may not. |
| 8FFB.1 | Calculating or generating timestamps, such as for logging purposes |
| 3D61.1 | Including boot time in an optional, user-initiated bug report; the value must not leave the device except as part of that report |
NSPrivacyAccessedAPICategoryDiskSpace)APIs like volumeAvailableCapacityKey and NSFileSystemFreeSize. Common reason codes:
| Code | When to use it |
|---|---|
| E174.1 | Checking whether there is enough disk space to write files, or cleaning up when space is low. The app must visibly react to disk space levels. |
| 85F4.1 | Displaying disk space to the user (in data units or media-time units). Cannot be sent over the internet. |
| 7D9E.1 | Including disk space info in an optional, user-initiated bug report |
| B728.1 | Health-related research apps using HealthKit |
NSPrivacyAccessedAPICategoryUserDefaults)The UserDefaults API. Common reason codes:
| Code | When to use it |
|---|---|
| CA92.1 | Reading/writing data that is only accessible to your own app (the most common case) |
| 1C8F.1 | Reading/writing data shared between apps, extensions, and App Clips in the same App Group |
| C56D.1 | Third-party SDK reading data written by the host app |
| AC6B.1 | Accessing managed app configuration (com.apple.configuration.managed) |
NSPrivacyAccessedAPICategoryActiveKeyboards)APIs that list installed or active keyboards.
| Code | When to use it |
|---|---|
| 3EC4.1 | The app itself is a custom keyboard app determining if it is the active keyboard |
| 54BD.1 | Presenting the correct customized UI based on active keyboards; the data must not leave the device |
Two keys work together to declare tracking behavior:
NSPrivacyTracking is a Boolean. Set it to true if your app or SDK uses data for tracking as Apple defines it: linking data collected from your app with data from other companies' apps, websites, or offline properties for advertising or data brokering purposes.
NSPrivacyTrackingDomains is an array of domain strings. If NSPrivacyTracking is true, list every domain your code contacts for tracking. If the user has not granted ATT (App Tracking Transparency) permission, iOS will automatically block network requests to these domains.
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>analytics.example.com</string>
<string>ads.example.com</string>
</array>
A practical note: even if you set NSPrivacyTracking to false, we recommend still including the NSPrivacyTrackingDomains key with an empty array (house practice, not an Apple requirement). It keeps the manifest complete and avoids ambiguity.
Here is a repeatable process you can run before every submission.
This is the same report Apple's review system generates. If something is missing here, it will be missing during review.
Search your codebase for these patterns:
# File timestamps
grep -rn "NSFileCreationDate\|NSFileModificationDate\|contentModificationDateKey\|NSURLCreationDateKey" .
# System boot time
grep -rn "systemUptime\|mach_absolute_time\|ProcessInfo.*systemUptime" .
# Disk space
grep -rn "volumeAvailableCapacity\|NSFileSystemFreeSize\|NSFileSystemSize" .
# User defaults
grep -rn "UserDefaults\|NSUserDefaults\|\[NSUserDefaults" .
# Active keyboards
grep -rn "activeInputModes\|UITextInputMode" .
Cross-reference every hit against your NSPrivacyAccessedAPITypes declarations.
For each SDK in your project:
PrivacyInfo.xcprivacy fileIf your app uses any analytics, advertising, or attribution SDKs:
NSPrivacyTrackingDomainsCompare your NSPrivacyCollectedDataTypes entries against what you declared on App Store Connect. They should match. Discrepancies are a review flag.
# Validate the XML is well-formed
plutil -lint PrivacyInfo.xcprivacy
# Convert to readable JSON for easier review
plutil -convert json -o - PrivacyInfo.xcprivacy | python3 -m json.tool
These are the patterns that account for the majority of privacy manifest rejections.
Missing manifest entirely. Your app calls UserDefaults (almost every app does) but has no PrivacyInfo.xcprivacy at all. This triggers ITMS-91053.
Outdated third-party SDKs. Your app's manifest is fine, but you are bundling an analytics SDK from 2023 that predates the requirement. Update the SDK or verify it includes its own manifest.
Invalid reason codes. Declaring reason code CA92.1 for a FileTimestamp API category. Reason codes are specific to their category, you cannot mix them.
Missing reason codes. You declare the API category but leave the reasons array empty, or omit a reason that your code actually requires.
Adding SDK declarations to your app manifest. Apple's guidance is explicit: do not add the privacy practices of an SDK to your app's manifest. Each SDK should carry its own. Xcode merges them automatically.
Declaring tracking as false while using tracking domains. If you list domains in NSPrivacyTrackingDomains but set NSPrivacyTracking to false, Apple sees a contradiction.
Not updating after adding new features. You add a file-management feature that reads modification dates, but forget to add the FileTimestamp API declaration. The manifest drifts out of sync with the binary.
Third-party SDKs are where most privacy manifest pain originates. Here is how to manage them.
Check Apple's list of commonly-used SDKs. Apple publishes a list of third-party SDKs that are expected to include their own privacy manifests. If your SDK is on that list and does not include one, your submission may be rejected regardless of what your own manifest says.
Pin SDK versions that include manifests. When you update a dependency, verify the new version still includes PrivacyInfo.xcprivacy. Some package managers strip resource bundles during integration.
Audit with the privacy report. After archiving, the Xcode Privacy Report shows manifests per SDK. If an SDK is missing from the report, its manifest did not get bundled correctly.
For SDKs you cannot update, consider:
Use automated scanning. Manually auditing manifests across dozens of dependencies does not scale. Tools like AppCompliance can continuously scan your app binary and its embedded SDKs, flag missing or incomplete privacy manifests, and alert you before you submit to App Store review. This turns a manual, error-prone checklist into a repeatable, automated gate in your CI/CD pipeline. The same idea extends to your whole dependency tree in our guide to auditing third-party SDKs.
Yes. If your app calls any required reason API, and nearly every app calls UserDefaults at minimum, you need a privacy manifest declaring that usage. The manifest is not only about data collection; it is about API access.
Apple sends a warning email with error codes like ITMS-91053 (missing API declaration) or ITMS-91055 (invalid API reason declaration); the email is the early warning, and the block comes when you submit the build for review. You will need to fix the manifest and resubmit, which adds days to your release cycle.
Yes. SwiftUI does not exempt you from privacy manifest requirements. SwiftUI apps still use UserDefaults, file APIs, and other required reason APIs under the hood.
Yes, and you should. Your app target has its own manifest, and each third-party SDK or framework should include its own. Xcode merges them into one Privacy Report at archive time.
The required reason API declaration applies to iOS, iPadOS, tvOS, watchOS, and visionOS. Apple's current documentation does not list macOS among the platforms that must declare required reason API usage, so a Mac app is not held to the same declaration rule as its iOS counterpart today. Treat that as a platform detail worth re-checking each year, since Apple has expanded this requirement steadily since it started.
At minimum, before every App Store submission. Ideally, audit as part of your CI pipeline so that any new API usage is caught before it reaches code review.
Privacy manifests are not going away. Apple is expanding their scope, not reducing it. Building a solid audit process now saves you from scrambling with every new requirement. Whether you audit manually or automate the process with a tool like AppCompliance, the key is making privacy validation a first-class step in your release workflow, not an afterthought. For the iOS road ahead, see our WWDC 2026 compliance preview.
Everything technical in this post is checkable from the build itself, and that is exactly what AppCompliance does: upload an iOS or Android build, and minutes later you have every issue that would get it rejected, with the exact fix next to it.
One email when we open the doors. No spam, just the launch.