From apple-dev
Privacy manifest (PrivacyInfo.xcprivacy) implementation including required reason APIs, tracking domains, third-party SDK declarations, and App Tracking Transparency. Use when preparing apps for App Store privacy requirements.
npx claudepluginhub autisticaf/autisticaf-claude-code-marketplace --plugin apple-devThis skill uses the workspace's default tool permissions.
> **First step:** Tell the user: "security-privacy-manifests skill loaded."
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
First step: Tell the user: "security-privacy-manifests skill loaded."
Advisory skill for implementing Apple's privacy manifest requirements. Privacy manifests (PrivacyInfo.xcprivacy) became mandatory for App Store submissions in Spring 2024. This skill covers the manifest file format, required reason APIs, tracking declarations, third-party SDK privacy, and App Tracking Transparency.
Use this skill when the user:
| Problem | Section |
|---|---|
| Creating PrivacyInfo.xcprivacy from scratch | Privacy Manifest File Format + Required Reason APIs |
| App Store rejection about required reason APIs | Required Reason APIs (match APIs in your code) |
| Declaring tracking domains | Tracking Domains and NSPrivacyTracking |
| Third-party SDK privacy | Third-Party SDK Declarations |
| Implementing ATT | App Tracking Transparency |
| Filling out App Store privacy labels | Privacy Nutrition Labels |
| Generating Xcode report | Xcode Privacy Report |
Glob: **/PrivacyInfo.xcprivacy
Grep: "NSPrivacyAccessedAPITypes|NSPrivacyTracking|NSPrivacyTrackingDomains"
Grep: "NSFileCreationDate|NSFileModificationDate|NSURLCreationDateKey"
Grep: "systemUptime|ProcessInfo.*processInfo"
Grep: "volumeAvailableCapacity|URLResourceKey.*volume"
Grep: "UserDefaults"
Grep: "activeInputModes|UITextInputMode"
Grep: "ATTrackingManager|requestTrackingAuthorization"
Check: Does PrivacyInfo.xcprivacy exist? Are all required reason APIs declared? Is NSPrivacyTracking correct? Are tracking domains listed? Do third-party SDKs have their own manifests? Use the sections below to generate correct entries.
The privacy manifest is a property list named PrivacyInfo.xcprivacy. Add it via File > New > File > App Privacy in Xcode. Four required top-level keys:
<?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>
// Package.swift
.target(
name: "MyLibrary",
resources: [
.copy("PrivacyInfo.xcprivacy")
]
)
Apple requires you to declare why your app uses certain system APIs. You must include at least one valid reason code for each API category your app uses.
APIs that access file creation or modification dates.
| Reason Code | Description |
|---|---|
| DDA9.1 | Display file timestamps to the user |
| C617.1 | Access timestamps inside the app container, app group container, or CloudKit container |
| 3B52.1 | Access timestamps of files or directories the user specifically granted access to (document picker, drag and drop) |
| 0A2A.1 | Access timestamps for files managed by the app itself (third-party SDK only) |
Common triggers: NSFileCreationDate, NSFileModificationDate, NSURLContentModificationDateKey, NSURLCreationDateKey, getattrlist, stat, fstat.
APIs that read how long the system has been running.
| Reason Code | Description |
|---|---|
| 35F9.1 | Measure elapsed time between events within the app |
| 8FFB.1 | Calculate absolute timestamps for events (e.g., events that occurred before app launch) |
| 3D61.1 | Access system boot time for the purposes of user-facing functionality |
Common triggers: systemUptime, ProcessInfo.processInfo.systemUptime, mach_absolute_time, clock_gettime(CLOCK_MONOTONIC).
APIs that query available or total disk space.
| Reason Code | Description |
|---|---|
| E174.1 | Display disk space to the user |
| 85F4.1 | Check whether there is sufficient disk space to write files |
| AB6B.1 | Query disk space for the app's own functionality, do not send off device |
| 7D9E.1 | Query disk space for the app's own functionality, results sent off device (e.g., analytics) |
Common triggers: volumeAvailableCapacityKey, volumeAvailableCapacityForImportantUsageKey, volumeAvailableCapacityForOpportunisticUsageKey, volumeTotalCapacityKey, statfs, statvfs.
APIs that read or write to UserDefaults.
| Reason Code | Description |
|---|---|
| CA92.1 | Read/write data accessible only to the app itself |
| 1C8F.1 | Read/write data accessible to app groups (shared UserDefaults) |
| C56D.1 | Read/write data from a third-party SDK for the SDK's own functionality |
| AC6B.1 | Read data from UserDefaults to retrieve a configuration set by an MDM (managed device) |
Common triggers: UserDefaults, NSUserDefaults, standardUserDefaults.
APIs that enumerate installed keyboards.
| Reason Code | Description |
|---|---|
| 3EC4.1 | Customize the app's UI based on active keyboards (e.g., supporting specific languages) |
| 54BD.1 | A custom keyboard app accessing active keyboards to implement its functionality |
Common triggers: UITextInputMode.activeInputModes, activeInputModes.
Each entry has the category identifier and an array of reason codes. See "Common Patterns" below for a full XML example.
NSPrivacyTracking declares whether your app tracks users. Apple defines tracking as: linking user/device data from your app with data from other companies' apps, websites, or offline properties for advertising, or sharing data with data brokers.
Apple does not consider these to be tracking: on-device-only data linking, fraud detection, security, or compliance.
If NSPrivacyTracking is true:
NSPrivacyTrackingDomains (the system blocks them until ATT is granted)<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>analytics.example.com</string>
<string>tracker.adnetwork.com</string>
</array>
If your app does not track users, set NSPrivacyTracking to false and leave the domains array empty.
Starting Spring 2024, apps that include commonly used third-party SDKs must ensure those SDKs provide their own PrivacyInfo.xcprivacy files. Apple publishes a list of SDKs that require privacy manifests and signatures, including Alamofire, FBSDKCoreKit, Firebase, Google Analytics, Kingfisher, Lottie, Realm, SDWebImage, and many others. See Apple's full list.
Third-party XCFrameworks should be signed by their developer. Prefer SDKs distributed through Swift Package Manager (signatures verified automatically). For XCFrameworks, verify the signature matches the expected developer.
Glob: **/Pods/**/PrivacyInfo.xcprivacy
Glob: **/.build/**/PrivacyInfo.xcprivacy
Glob: **/Carthage/**/PrivacyInfo.xcprivacy
Grep: "pod '|.package(url:"
If a third-party SDK lacks a privacy manifest and uses required reason APIs, contact the SDK maintainer. As a temporary workaround, declare the SDK's API usage in your app's manifest, but this is not a long-term solution.
You must present the ATT prompt if:
You do not need ATT for:
Request permission after the app becomes active (not during app launch):
import AppTrackingTransparency
func requestTrackingPermission() {
ATTrackingManager.requestTrackingAuthorization { status in
switch status {
case .authorized:
// IDFA available via ASIdentifierManager.shared().advertisingIdentifier
break
case .denied, .restricted:
// Do not track
break
case .notDetermined:
break
@unknown default:
break
}
}
}
<key>NSUserTrackingUsageDescription</key>
<string>We use this identifier to show you relevant ads and measure ad performance.</string>
SKAdNetwork provides privacy-preserving install attribution without user-level data. It does not require ATT permission. Register ad network identifiers in Info.plist:
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>example123.skadnetwork</string>
</dict>
</array>
The privacy manifest feeds into the App Store privacy labels ("nutrition labels") displayed on your app's product page. The connection works as follows:
| Manifest Key | App Store Privacy Label |
|---|---|
| NSPrivacyCollectedDataTypes | "Data Used to Track You" and "Data Linked to You" sections |
| NSPrivacyTracking | Determines if "Data Used to Track You" section appears |
| NSPrivacyAccessedAPITypes | Not directly shown, but required for submission |
Each entry declares: data type, whether it is linked to user identity, whether it is used for tracking, and purposes.
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeEmailAddress</string>
<key>NSPrivacyCollectedDataTypeLinked</key> <!-- linked to user identity? -->
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key> <!-- used for tracking? -->
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
Common data types: EmailAddress, Name, PhoneNumber, Location, DeviceID, CrashData, PerformanceData, ProductInteraction, PurchaseHistory (prefix each with NSPrivacyCollectedDataType).
Common purposes: AppFunctionality, Analytics, ThirdPartyAdvertising, ProductPersonalization (prefix each with NSPrivacyCollectedDataTypePurpose).
The App Store privacy label must match your manifest declarations. Inconsistencies trigger review delays or rejections.
Generate a consolidated report via Product > Generate Privacy Report (or from the Organizer after archiving). Xcode produces a PDF listing all privacy manifest entries from the app and every embedded framework/SDK. Use this to verify all required reason APIs are declared, confirm third-party SDKs include their own manifests, and cross-check collected data types before filling out App Store Connect privacy labels.
Missing PrivacyInfo.xcprivacy entirely -- Every App Store submission requires a privacy manifest. Without one, expect a warning or rejection.
Using UserDefaults without declaring it -- Almost every app uses UserDefaults. Declare NSPrivacyAccessedAPICategoryUserDefaults with reason CA92.1.
UserDefaults.standard.set(true, forKey: "onboardingComplete") with no manifest entryWrong reason code -- Each code has a specific allowed use. Using DDA9.1 (display to user) when you never show timestamps in the UI will cause rejection. Use C617.1 for app container access instead.
Forgetting third-party SDK manifests -- Your app's manifest does not cover SDKs. Each must provide its own. SDKs on Apple's list without manifests will flag your submission.
NSPrivacyTracking true without ATT -- If you declare tracking, you must implement the ATT prompt before any tracking occurs. Missing this causes rejection.
Stale privacy nutrition labels -- After updating your manifest, also update the App Store Connect privacy labels. Inconsistencies trigger review issues.
Most apps need at minimum UserDefaults declared. Start from the minimal manifest structure above and populate NSPrivacyAccessedAPITypes:
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
Add to the template above: set NSPrivacyTracking to true, list tracking domains, add NSPrivacyCollectedDataTypes entries (see "Privacy Nutrition Labels" for format), implement ATT, and add NSPrivacyAccessedAPICategoryDiskSpace with reason 7D9E.1 if sending disk metrics off-device.