Blogs
Unity iOS Privacy Manifest Guide: Required Reason APIs, Plug-ins, and ITMS Errors
Last updated: September 27, 2026
A Unity iOS submission can contain privacy declarations from at least three owners: your game or app, the Unity engine, and third-party plug-ins. App Store Connect evaluates the packaged result, not the tidy structure visible in the Unity Editor. That is why adding one PrivacyInfo.xcprivacy file to the Xcode project can appear to fix one warning while leaving a plug-in's ITMS-91061 failure untouched.
The reliable workflow is to identify the bundle Apple named, decide which owner is responsible, and then inspect the exported archive. This guide follows Unity's own privacy-manifest guidance and Apple's SDK ownership rules.
Quick answer: put app-owned declarations in a manifest tracked with the Unity project, verify Unity's engine declarations for the version you ship, and require every affected third-party framework or plug-in to provide its own manifest. Never copy a plug-in's declarations into the main app manifest as a shortcut for ITMS-91061.
Understand the three manifest owners
| Owner | Examples | Where the durable fix belongs |
|---|---|---|
| Your application | Native code you wrote, data collection you control, app-specific tracking domains | The app's source-controlled privacy manifest |
| Unity engine | PlayerPrefs, AssetBundle disk checks, engine timing and file APIs | A supported Unity version and Unity-provided engine manifest |
| Third-party plug-in or SDK | Ads, analytics, sign-in, notifications, attribution, social SDKs | The plug-in or SDK bundle and its vendor release |
Unity's current Apple privacy manifest policy documentation says third-party SDKs, packages, and plug-ins must provide their own manifests when applicable. Apple's third-party SDK requirements also list UnityFramework and many SDKs commonly embedded in Unity games.
Classify the App Store Connect error
ITMS-91053: Missing API declaration
Apple detected a Required Reason API category but did not find an accepted reason covering the use. Determine whether the call comes from your code, Unity engine code, or a plug-in before choosing a reason.
ITMS-91056: Invalid privacy manifest
Apple found a manifest but rejected its structure or values. The error path matters: it may point to the app manifest, UnityFramework.framework, or a third-party framework inside the exported app.
ITMS-91061: Missing privacy manifest
Apple identified a privacy-impacting third-party SDK without its required manifest. Upgrade or correct the SDK itself. Adding the SDK's declarations to the top-level application manifest is not the safe fix.
Use the App Store Privacy Error Checker to extract the error code, framework path, SDK name, and API category from the email. Everything stays in the browser. Keep the original path with your release evidence.
Step 1: record the Unity build context
Before changing packages, record:
- Unity editor version and patch level.
- iOS Build Support module version.
- Scripting backend and architecture.
- Installed packages from Package Manager.
- Native
.framework,.xcframework,.a, and.bundlefiles underAssets/Plugins. - Custom post-process build scripts.
- The exact Xcode archive and build number Apple analyzed.
The same C# project can produce a different native bundle graph after a Unity upgrade or package change. Without the build context, a successful resubmission does not tell you which component fixed the problem.
Step 2: inventory manifests and native plug-ins in Unity
From the Unity project root, list source manifests:
find Assets Packages -name PrivacyInfo.xcprivacy -print 2>/dev/null
Then inventory native dependencies:
find Assets/Plugins -type f \
\( -name "*.framework" -o -name "*.xcframework" -o -name "*.a" -o -name "*.bundle" \) \
-print
Package Manager content may be cached outside Assets, so also review the resolved Packages/manifest.json and Packages/packages-lock.json. For each SDK named in Apple's email, identify the Unity package or asset that delivered it.
If a plug-in contains a manifest, select it in the Unity Editor and verify that its Plugin Inspector settings include iOS. A file present in the repository but excluded from the platform will not reach the exported Xcode project.
Step 3: create the app-owned manifest
Unity instructs app developers to create the privacy manifest and save it under Assets/Plugins. Teams often use an iOS-specific subfolder such as Assets/Plugins/iOS, but the important points are that the file is source controlled, enabled for iOS, and copied into the correct application target.
A minimal Required Reason API section has this shape:
<?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>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
</dict>
</plist>
Do not use this example simply because the app calls PlayerPrefs. Current supported Unity versions already document engine-owned declarations. Add an app declaration only when it accurately represents behavior your application owns and the approved reason conditions are satisfied.
Read Apple's current Required Reason API documentation before committing a reason. The Required Reason API Checker can detect known category/code mismatches, but it cannot decide whether a reason truthfully describes your feature.
Step 4: understand Unity's documented engine reasons
Unity 6.0 documentation lists the following engine declarations:
| Category | Documented reason | Unity behavior |
|---|---|---|
| File timestamp APIs | 0A2A.1 | C# timestamp APIs |
| File timestamp APIs | C617.1 | File checks |
| User defaults APIs | CA92.1 | PlayerPrefs |
| System boot time APIs | 35F9.1 | Calculating time between events |
| Disk space APIs | E174.1 | AssetBundle disk-space checks |
This table is not a template for adding all five reasons to every app. It is a diagnostic map for understanding engine calls. Verify the documentation for the exact Unity release you ship, because package contents and generated manifests can change between editor versions.
If ITMS-91053 names one of these categories and the archive lacks the Unity engine manifest, upgrade to a supported Unity patch and inspect the exported UnityFramework.framework. Do not mask a missing engine resource by declaring unrelated app behavior.
Step 5: handle third-party plug-ins separately
Advertising, analytics, attribution, authentication, and notification plug-ins often embed their own native frameworks. For each plug-in:
- Find the native framework named in Apple's message.
- Identify the Unity asset or package that delivered it.
- Check the vendor's current iOS release notes for privacy-manifest support.
- Upgrade the plug-in and its embedded SDK together.
- If no supported version exists, replace, remove, or obtain a corrected build from the vendor.
- Confirm the manifest is inside the plug-in or SDK bundle after export.
If you are the plug-in author, put the declarations with the native code they describe. A .framework should contain its own accurate PrivacyInfo.xcprivacy when required. If you distribute loose native source instead, ensure the manifest is included as an iOS resource and document the integration for downstream Unity developers.
For ITMS-91061, do not copy a vendor's manifest into the top-level app and call the issue complete. Apple's requirement applies to the privacy-impacting SDK identified in the email. The ITMS-91061 guide explains why the SDK bundle is the repair target.
Step 6: validate XML and manifest semantics
Validate the source file before exporting:
plutil -lint Assets/Plugins/iOS/PrivacyInfo.xcprivacy
plutil -p Assets/Plugins/iOS/PrivacyInfo.xcprivacy
Adjust the path to match your project. Then use the PrivacyInfo.xcprivacy Validator to check:
- Supported top-level keys.
- The expected value type for every key.
- Empty arrays and empty strings.
- Required Reason API categories and codes.
- Tracking-domain formatting.
A tracking domain must be a hostname, not a URL. This is invalid:
https://analytics.example.com/collect/?game=1
The domain value would be written as:
analytics.example.com
Whether it belongs in NSPrivacyTrackingDomains depends on actual tracking behavior and consent—not only its syntax.
For ITMS-91056, validate the exact manifest path reported by Apple. Apple's TN3181 is the primary debugging reference.
Step 7: inspect the exported Xcode project
After Unity exports the iOS project, search it before opening Xcode:
find /path/to/Unity-iPhone -name PrivacyInfo.xcprivacy -print
In Xcode, verify:
- The app-owned manifest belongs to the
Unity-iPhoneapplication target. - Unity's engine manifest is packaged with
UnityFrameworkfor the shipped editor version. - Each affected third-party framework contains or correctly resources its own manifest.
- Custom post-process scripts did not rename, replace, or drop a manifest.
- Duplicate resources do not cause one manifest to overwrite another.
If you use a PostProcessBuild script, inspect its output rather than assuming the script still matches the generated Xcode project structure. Build-pipeline code written before privacy manifests existed is a common place for resource-copy omissions.
Step 8: inspect the archive that will be uploaded
Create a Release archive in Xcode. Then list all packaged manifests:
find /path/to/Unity-iPhone.xcarchive -name PrivacyInfo.xcprivacy -print
Validate every result:
find /path/to/Unity-iPhone.xcarchive -name PrivacyInfo.xcprivacy -print0 \
| xargs -0 -n1 plutil -lint
Follow the framework path from Apple's email into:
Products/Applications/YourGame.app/Frameworks/
The archive should demonstrate that the responsible bundle contains a valid manifest. A correct file under Assets/Plugins is not enough if the export or Xcode build drops it.
Common Unity failure patterns
The manifest disappears after every export
The source file is not imported for iOS, or a custom build script owns the generated project. Fix the Unity source and pipeline rather than manually editing each Xcode export.
ITMS-91056 names an advertising framework
Validate that framework's manifest, update the advertising SDK, and avoid replacing it with the app manifest. The vendor owns the framework declaration.
ITMS-91061 persists after adding an app manifest
This is expected when Apple named a third-party SDK. Upgrade or replace the SDK and verify its bundle in the archive.
A reason code works for another Unity game
That does not make it valid for this game. Approved reasons describe behavior, not merely API symbols or engine choice.
The repository contains several manifests with the same filename
That can be correct when they belong to separate bundles. The filename is standardized; bundle ownership and packaged location distinguish the declarations.
Final Unity submission checklist
- Unity editor, package, plug-in, and SDK versions are recorded.
- Every Apple error path is mapped to its owning bundle.
- App-owned declarations are tracked under
Assets/Pluginsand enabled for iOS. - Unity engine declarations match the shipped editor version.
- Third-party plug-ins provide their own manifests where required.
- All source and archived manifests pass
plutil -lint. - Tracking domains contain no scheme, path, query, fragment, or trailing slash.
- The archive—not only the Unity project—contains the expected files.
- A developer confirms each reason against actual app or SDK behavior.
This guide cannot guarantee App Review approval and is not legal advice. Privacy manifests are technical declarations about the exact binary you ship, so re-check them whenever Unity, a package, or a native SDK changes.
Parse the rejection email and validate the manifest locally before exporting another Unity iOS build.
Check My Privacy Manifest