Apple added the privacy manifest requirement to App Store submissions in 2024. The file — PrivacyInfo.xcprivacy — is an XML property list that declares which privacy-sensitive APIs your app accesses, what data it collects, whether it uses cross-app tracking, and which tracking domains it contacts. Get it wrong and your binary gets rejected. Get it very wrong and Apple's review notes will describe exactly which key is invalid.
The obvious shortcut is to paste your Podfile or package.json into ChatGPT and ask it to write the manifest. ChatGPT will produce XML that looks correct. It uses the right keys, the structure is valid, and it references real Apple documentation names. The problem is that it makes four specific errors, almost every time, and Apple's automated pipeline catches all four.
What the file actually is
A PrivacyInfo.xcprivacy file is a standard Apple property list (plist) with four top-level keys:
NSPrivacyTracking— a boolean.trueif your app uses data for cross-app tracking as defined by Apple's App Tracking Transparency framework.NSPrivacyTrackingDomains— an array of domain strings that receive tracking data. Required whenNSPrivacyTrackingistrue.NSPrivacyAccessedAPITypes— an array of dictionaries, one per privacy-sensitive API category your app calls (UserDefaults, file timestamps, system boot time, disk space, etc.). Each dictionary includes the API type and an array of reason codes.NSPrivacyCollectedDataTypes— an array describing what data your app collects, how it's used, whether it's linked to identity, and whether it's used for tracking.
Apple's full specification is at developer.apple.com/documentation/bundleresources/privacy-manifest-files.
The manifest must be accurate. It's not a legal disclaimer — Apple validates it against your binary's actual API calls.
The four errors ChatGPT makes, every time
Error 1: Missing NSPrivacyTracking when cross-app tracking SDKs are present
When your app includes Meta Audience Network, AppsFlyer, Facebook Login, or similar SDKs, NSPrivacyTracking must be true. ChatGPT frequently omits this, or sets it to false, when it sees these dependencies.
What ChatGPT produces:
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
What's wrong: Meta Audience Network and AppsFlyer use data across apps and websites to target and measure advertising. Apple's definition of "tracking" under ATT is explicit: linking user or device data collected from your app with third-party data for advertising or advertising measurement. If you have these SDKs and NSPrivacyTracking is false, your manifest contradicts what Apple can see in your binary.
Reference: Apple's Privacy Manifest Files documentation, section "NSPrivacyTracking."
Correct:
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>graph.facebook.com</string>
<string>an.facebook.com</string>
<string>analytics.appsflyer.com</string>
</array>
Error 2: Wrong NSPrivacyAccessedAPITypeReasons code for UserDefaults
NSUserDefaults is one of Apple's Required Reason APIs — if your app or any linked SDK accesses it, you declare a reason code. ChatGPT often picks 1C8F.1 from the docs without checking whether your app actually uses an App Group.
What ChatGPT produces:
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>1C8F.1</string>
</array>
</dict>
What's wrong: 1C8F.1 means "access UserDefaults for data shared within an App Group — apps, app extensions, and App Clips in the same group." It only applies if your app declares an App Group. For a single-target app storing its own preferences or SDK configuration (the common case), the correct code is CA92.1 — "UserDefaults for data exclusive to the app itself." Firebase Core, Crashlytics, and the rest of the firebase-ios-sdk modules declare CA92.1 in their own published manifests. You can check this yourself in github.com/firebase/firebase-ios-sdk — search for PrivacyInfo.xcprivacy.
Valid codes for NSPrivacyAccessedAPICategoryUserDefaults are CA92.1, 1C8F.1, C56D.1, and AC6B.1. Pick the one that matches what your code actually does, not the first one in the docs.
Reference: Apple's TN3183: Adding required reason API entries to your privacy manifest.
Correct (for a single-target app):
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
If your app uses an App Group (extensions, widgets, App Clips sharing defaults), 1C8F.1 is correct — alongside or instead of CA92.1.
Error 3: Conflating Firebase SDK modules with Firebase Analytics tracking
When NSPrivacyTracking is true, every domain that receives tracking data must appear in NSPrivacyTrackingDomains. ChatGPT gets this wrong in a specific way: it assumes "Firebase" equals "tracking" and lists Firebase service endpoints as tracking domains, when most Firebase modules don't actually track under Apple's ATT definition.
What ChatGPT produces (for an app using Firebase Auth + Crashlytics):
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>firebase.googleapis.com</string>
<string>crashlyticsreports-pa.googleapis.com</string>
</array>
What's wrong: Check Firebase's own published manifests. FirebaseCore, FirebaseAuth, FirebaseMessaging, Crashlytics, Firestore, FirebaseRemoteConfig — all declare NSPrivacyTracking: false with empty NSPrivacyTrackingDomains arrays in firebase-ios-sdk on GitHub. They don't track. Firebase service endpoints like firebase.googleapis.com are backend connections, not ATT-tracking domains.
The one Firebase product that does track is GoogleAppMeasurement (the SDK that powers Firebase Analytics) — distributed separately from firebase-ios-sdk. Its tracking domain is app-measurement.com. If your app doesn't use Firebase Analytics specifically, NSPrivacyTracking can be false and the domain array can be empty even with every other Firebase module linked in.
Correct (Firebase Analytics / GoogleAppMeasurement in use):
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>app-measurement.com</string>
</array>
Correct (Firebase Auth + Crashlytics, no Analytics):
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
Reference: firebase-ios-sdk publishes a PrivacyInfo.xcprivacy per module — verify directly. Apple's WWDC 2023 session "Get started with privacy manifests" covers the ATT definition of tracking.
Note: verify against your SDK versions — manifests can change between releases, and NSPrivacyTrackingDomains for other tracking SDKs (Meta Audience Network, AppsFlyer, Branch) must be listed separately.
Error 4: Wrong file location or malformed plist structure
A valid PrivacyInfo.xcprivacy file must be placed at a specific location in your Xcode project and use correct plist structure. ChatGPT gets both wrong with some regularity.
What ChatGPT produces:
<?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">
<key>NSPrivacyTracking</key>
<false/>
</plist>
What's wrong: The top-level element inside <plist> must be a <dict>, not bare keys. And the file belongs in your app target's bundle resources, not in a target-specific subfolder ChatGPT sometimes suggests (like YourApp/Resources/PrivacyInfo.xcprivacy).
Reference: Apple's Bundle Resources documentation specifies that the file must be named PrivacyInfo.xcprivacy and included in the app target's Copy Bundle Resources build phase.
Correct 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>NSPrivacyAccessedAPITypes</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
</dict>
</plist>
Correct location: Add the file directly under your main app target in Xcode, then confirm it appears in Build Phases → Copy Bundle Resources.
What Pageguard generates instead
When you run an app scan — either by pasting your Podfile / package.json or connecting your repo — Pageguard reads your actual dependency list and matches it against a library of 216 SDK signatures. The output is a PrivacyInfo.xcprivacy file with NSPrivacyTracking set based on whether you actually have tracking SDKs, NSPrivacyAccessedAPITypeReasons populated with the codes that match your SDK usage patterns, and NSPrivacyTrackingDomains derived from known endpoints for each detected SDK. It's not a template — it's generated from what's in your project. If you want to see how Pageguard compares to generating documents manually or with a general-purpose AI, the vs ChatGPT page walks through the methodology difference.
The honest version
If you have time to read through Apple's Required Reason APIs documentation, match each SDK in your Podfile to the right reason codes, find the current domain lists from each SDK vendor's published privacy manifest, and verify all of it against your binary before every submission — do that. It's accurate and free.
If you don't have that time before your next build, use something that does it from your dependency file. Run an app scan on Pageguard — paste your package.json or Podfile and get the XML in under a minute.