```html SwiftUI: How to Build a Privacy Manifest (iOS 17+, 2026)

How to Build a Privacy Manifest in SwiftUI

iOS 17+ Xcode 16+ Intermediate APIs: PrivacyInfo.xcprivacy Updated: May 12, 2026
TL;DR

Add a PrivacyInfo.xcprivacy property list to your Xcode target, then declare your tracking intent, collected data types, and required-reason API mappings — Apple rejects submissions that omit this file or use undeclared system APIs.

<?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>

Full implementation

A real-world app typically reads UserDefaults, checks file timestamps, and may access disk space — each of these is a "required-reason API" that Apple now audits at submission time. The manifest below is a realistic starting point for a SwiftUI productivity app: no tracking, no third-party analytics, but three common system API accesses properly justified.

Create the file in Xcode via File › New › File from Template… › Privacy Manifest. Make sure the Target Membership checkbox is ticked for your app target (not just the test target). Then paste or edit the XML below.

<?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. Tracking ─────────────────────────────────────────── -->
  <!-- Set to true only if you use IDFA or fingerprint across apps -->
  <key>NSPrivacyTracking</key>
  <false/>

  <!-- Domains used for tracking (empty if NSPrivacyTracking is false) -->
  <key>NSPrivacyTrackingDomains</key>
  <array/>

  <!-- ── 2. Collected data types ─────────────────────────────── -->
  <key>NSPrivacyCollectedDataTypes</key>
  <array>
    <dict>
      <!-- User-generated content (e.g. notes the user types) -->
      <key>NSPrivacyCollectedDataType</key>
      <string>NSPrivacyCollectedDataTypeOtherUserContent</string>
      <key>NSPrivacyCollectedDataTypeLinked</key>
      <false/>
      <key>NSPrivacyCollectedDataTypeTracking</key>
      <false/>
      <key>NSPrivacyCollectedDataTypePurposes</key>
      <array>
        <string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
      </array>
    </dict>
  </array>

  <!-- ── 3. Required-reason APIs ─────────────────────────────── -->
  <key>NSPrivacyAccessedAPITypes</key>
  <array>

    <!-- UserDefaults: storing app preferences -->
    <dict>
      <key>NSPrivacyAccessedAPIType</key>
      <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
      <key>NSPrivacyAccessedAPITypeReasons</key>
      <array>
        <!-- CA92.1: read/write own app prefs -->
        <string>CA92.1</string>
      </array>
    </dict>

    <!-- File timestamp: checking when a local document was last modified -->
    <dict>
      <key>NSPrivacyAccessedAPIType</key>
      <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
      <key>NSPrivacyAccessedAPITypeReasons</key>
      <array>
        <!-- C617.1: display to user or process their own files -->
        <string>C617.1</string>
      </array>
    </dict>

    <!-- Disk space: showing "storage used" in settings screen -->
    <dict>
      <key>NSPrivacyAccessedAPIType</key>
      <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
      <key>NSPrivacyAccessedAPITypeReasons</key>
      <array>
        <!-- E174.1: prevent disk-full writes on behalf of user -->
        <string>E174.1</string>
      </array>
    </dict>

  </array>

</dict>
</plist>

After editing, run xcrun privacy-manifest validate PrivacyInfo.xcprivacy from your project root to catch schema errors before submission.

How it works

  1. NSPrivacyTracking — the top-level boolean that tells Apple whether your app participates in cross-app or cross-website tracking as defined by ATT. Setting it to false and leaving NSPrivacyTrackingDomains empty is correct for apps that don't use IDFA or probabilistic fingerprinting.
  2. NSPrivacyCollectedDataTypes — an array of dictionaries, one per category of data your app collects. Each entry names the data category (e.g. NSPrivacyCollectedDataTypeOtherUserContent), declares whether it is linked to identity, whether it is used for tracking, and lists the collection purposes from Apple's fixed vocabulary.
  3. NSPrivacyAccessedAPITypes / NSPrivacyAccessedAPIType — this is the key that tripped up many developers at WWDC 23. Any call to UserDefaults, file-timestamp APIs (URLResourceValues.contentModificationDate), disk-space APIs (URLResourceValues.volumeAvailableCapacity), or system boot time must appear here with a reason code.
  4. Reason codes — Apple publishes a fixed list per API category (e.g. CA92.1 for UserDefaults storing your own prefs). You must pick the code that honestly matches your use case. Submitting an inapplicable code can trigger rejection on re-review.
  5. Third-party SDKs — starting Spring 2024 Apple also requires privacy manifests from SDKs (e.g. Firebase, Amplitude). Those ship their own PrivacyInfo.xcprivacy; Xcode merges all of them at archive time. You can inspect the merged report via Product › Archive › Validate App › Generate Privacy Report.

Variants

App that uses analytics (tracking enabled)

If you send events to a first-party analytics domain and cross-reference them with device identity, set NSPrivacyTracking to true and list every HTTPS domain involved. You must also request ATT permission with AppTrackingTransparency before any tracked network call.

<key>NSPrivacyTracking</key>
<true/>

<key>NSPrivacyTrackingDomains</key>
<array>
  <string>analytics.myapp.com</string>
  <string>events.myapp.com</string>
</array>

<!-- Also add NSPrivacyCollectedDataType entries for
     NSPrivacyCollectedDataTypeDeviceID and
     NSPrivacyCollectedDataTypeProductInteraction,
     both with NSPrivacyCollectedDataTypeTracking = true -->

SDK / framework target

If you're shipping a Swift Package or XCFramework that others embed, add your own PrivacyInfo.xcprivacy inside the package root alongside Package.swift. Apple's toolchain bundles it automatically. Declare only the APIs and data your library accesses directly — your users' host-app manifests cover the rest. For SPM packages, add the file to the target's resources array:

// Package.swift
.target(
    name: "MySDK",
    resources: [
        .process("PrivacyInfo.xcprivacy")
    ]
)

Common pitfalls

Prompt this with Claude Code

When using Soarias or Claude Code directly to implement this:

Implement privacy manifest in SwiftUI for iOS 17+.
Use PrivacyInfo.xcprivacy.
Scan the project for UserDefaults, file-timestamp, disk-space,
and system-boot-time API calls, then generate a PrivacyInfo.xcprivacy
that maps each usage to the correct NSPrivacyAccessedAPITypeReasons code.
Set NSPrivacyTracking to false unless IDFA is used.
Make it accessible (VoiceOver labels).
Add a #Preview with realistic sample data.

In the Soarias Build phase, Claude Code can scan your SwiftUI source tree for required-reason API calls and auto-populate the manifest before you archive — cutting the most common submission rejection reason to zero.

Related

FAQ

Does this work on iOS 16?

The PrivacyInfo.xcprivacy file is a build-time artifact — it ships inside your .ipa and is read by App Store Connect servers, not by the OS at runtime. This means the file itself has no minimum deployment target: it's required for any submission built with Xcode 15+ regardless of whether your app supports iOS 16 or iOS 17. However, Apple began enforcing the manifest requirement for all apps in Spring 2024, so even iOS 16-targeting apps need it.

How do I find every required-reason API my app uses?

The most reliable method is Xcode's built-in audit: archive your app, open Organizer, select the archive, click Validate App with your distribution certificate, and choose Generate Privacy Report. The report lists every required-reason API Apple's static analyzer found in your binary and linked frameworks, along with the reason codes you've declared (or omitted). You can also run grep -r "UserDefaults\|contentModificationDate\|volumeAvailableCapacity\|systemUptime" . in your source tree as a quick sanity check.

What's the UIKit equivalent?

PrivacyInfo.xcprivacy is framework-agnostic — it applies identically to UIKit, SwiftUI, AppKit, and mixed codebases. The file format, key names, and reason codes are the same regardless of your UI layer. If you're migrating a UIKit app to SwiftUI, your existing manifest (if you have one) carries over without changes.

Last reviewed: 2026-05-12 by the Soarias team.

```