Privacy Manifests Break in Multi Module iOS Apps. Here Is Why
20 Feb 2026 · 7 min read · Erik van Kammen
If your iOS project has one target, one team, and a handful of dependencies, managing privacy manifests is straightforward. Add a PrivacyInfo.xcprivacy file, declare your API usage reasons, and move on.
Most real projects aren't that simple.
Multi-module architectures, shared frameworks, white-label apps, and large dependency graphs all create situations where privacy manifest management gets complicated fast.
Here's what that looks like in practice and how to manage it.
Apple processes privacy manifests at the bundle level. Each target in your Xcode project, and each embedded framework, can include its own PrivacyInfo.xcprivacy.
When Apple reviews your submission, the effective privacy manifest is the combination of all manifests found in the app bundle and its embedded frameworks.
This means:
Apple evaluates all manifests found in the bundle hierarchy. Each framework is expected to declare its own API usage. In practice, the app-level manifest can cover gaps, but Apple's guidance is that each SDK should include its own manifest. Missing coverage in any component creates a gap.
In a modular iOS project, code is split across internal frameworks or Swift packages. A typical setup might look like:
MainApp
├── CoreNetworking.framework
├── Analytics.framework
├── UIComponents.framework
├── FeatureAuth.framework
└── FeaturePayments.framework
Each of these modules can use required reason APIs. CoreNetworking might use UserDefaults. Analytics might call mach_absolute_time(). UIComponents might access file timestamps.
Where does the privacy manifest go?
Put a single PrivacyInfo.xcprivacy in the main app target. Declare all API usage reasons there, covering all internal modules.
Pros:
Cons:
This works well for smaller teams with a moderate number of internal modules. It doesn't satisfy Apple's requirement that third-party SDKs on the commonly-used SDK list include their own manifests.
Each module includes its own PrivacyInfo.xcprivacy declaring only the APIs it uses.
Pros:
Cons:
This is the approach that scales better for larger teams and organizations that share modules across apps.
The main app target has a manifest covering app-level API usage. Internal frameworks that are shared across multiple apps have their own manifests. Small, app-specific modules rely on the app-level manifest.
This is what most large teams end up with in practice. It balances ownership clarity with maintenance burden.
| Strategy | Best For | Ownership | Maintenance | Coverage Risk |
|---|---|---|---|---|
| Centralized | Small teams, 1-2 modules | Single owner | Low | Drift if modules change |
| Distributed | Large teams, many modules | Per-module owner | Higher | Gaps if modules skip |
| Hybrid | Multi-team, shared SDKs | Mixed | Medium | Balanced |
Your internal modules aren't the only consideration. Third-party SDKs need coverage too.
Current state of the ecosystem:
When a third-party SDK doesn't include a privacy manifest, you have two options:
Option 1 works as a short-term fix, particularly for SDKs not on Apple's commonly-used SDK list. For SDKs on that list, Apple may require the SDK itself to include a manifest. Option 2 is always the right long-term fix.
For XCFrameworks distributed as precompiled binaries, you can't easily add a manifest to the framework itself. Cover the gap in your app-level manifest.
The hardest part isn't writing the manifests. It's knowing if you've covered everything.
In Xcode's Organizer, select your archive and generate a privacy report. This shows detected API usage and the manifests that cover it.
Limitations: this report is based on static analysis of the archive. It's useful but not always complete, especially for dynamic or runtime API calls.
Add a build phase script that checks for PrivacyInfo.xcprivacy in each embedded framework. If a framework is missing one and isn't covered by your app-level manifest, fail the build.
# Check for privacy manifests in embedded frameworks
FRAMEWORKS_DIR="${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -d "$FRAMEWORKS_DIR" ]; then
for framework in "$FRAMEWORKS_DIR"/*.framework; do
if [ ! -f "$framework/PrivacyInfo.xcprivacy" ]; then
echo "warning: $(basename $framework) has no privacy manifest"
fi
done
fi
This doesn't tell you if the manifests are correct, but it catches missing ones early.
After building the IPA, scan the compiled binary with binary analysis to detect actual API usage and compare it against declared reasons. This is the most accurate check because it evaluates what Apple will evaluate.
If a module declares UserDefaults usage but the app target also uses UserDefaults for different purposes, you might need entries in both manifests with different reason codes.
Refactoring modules (splitting, merging, extracting to packages) can leave privacy manifest gaps. The API usage moves to a different target, but the manifest stays in the old location.
Having the same API category and reason code in multiple manifests isn't a problem for Apple (they merge them). But it creates maintenance confusion. Pick a clear strategy and document it.
Test targets that embed the same frameworks don't ship to users, but they can pollute your privacy report if you're not careful about which target you're analyzing.
SPM packages that produce resource bundles can include their own PrivacyInfo.xcprivacy. Pure source packages without resource bundles are covered by the consuming target's manifest. Not all SPM packages include a manifest. When adopting a new SPM dependency, check whether it does. The privacy report in Xcode helps surface gaps here.
Privacy manifests cover more than required reason APIs. They also declare tracking status (NSPrivacyTracking), tracking domains (NSPrivacyTrackingDomains), and collected data types (NSPrivacyCollectedDataTypes). In multi-module projects, tracking domain declarations are particularly tricky because different modules may contact different domains. These need to be declared in the appropriate manifest.
The goal is to make privacy manifest maintenance boring and predictable. Not something you scramble to fix during submission.
AppCompliance scans the compiled IPA and maps actual API usage against declared privacy manifest entries. It flags gaps, including coverage missing from third-party frameworks and their SDK inventory. This gives you a clear picture before submission. No tool guarantees that Apple will approve your app, but catching missing declarations before review avoids unnecessary delays.
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.