diff --git a/src/Packages/Audience/Editor/iOSPrivacyManifestPostProcessor.cs b/src/Packages/Audience/Editor/iOSPrivacyManifestPostProcessor.cs
new file mode 100644
index 000000000..2f39b2a10
--- /dev/null
+++ b/src/Packages/Audience/Editor/iOSPrivacyManifestPostProcessor.cs
@@ -0,0 +1,113 @@
+#nullable enable
+
+using System.IO;
+using UnityEditor;
+using UnityEditor.Callbacks;
+using UnityEngine;
+#if UNITY_IOS
+using UnityEditor.iOS.Xcode;
+#endif
+
+namespace Immutable.Audience.Editor
+{
+ ///
+ /// Patches UnityFramework/PrivacyInfo.xcprivacy to add IDFA tracking
+ /// declarations when AUDIENCE_MOBILE_ATTRIBUTION is enabled.
+ /// Unity auto-merges the default manifest; this post-processor adds
+ /// NSPrivacyTracking=true and NSPrivacyCollectedDataTypeAdvertisingData
+ /// in-place so Unity's own Required Reason API entries are preserved.
+ /// Runs at callbackOrder 9052, after the Info.plist (9050) and framework (9051) post-processors.
+ ///
+ internal static class iOSPrivacyManifestPostProcessor
+ {
+ internal const int CallbackOrder = 9052;
+ private const string BuiltManifestName = "PrivacyInfo.xcprivacy";
+
+ [PostProcessBuild(CallbackOrder)]
+ internal static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
+ {
+ if (target != BuildTarget.iOS) return;
+
+#if UNITY_IOS
+ if (!AttributionDefineEnabled()) return;
+
+ var builtManifestPath = FindBuiltManifest(pathToBuiltProject);
+ if (builtManifestPath == null)
+ {
+ Debug.LogWarning(
+ $"[ImmutableAudience] iOS privacy manifest post-processor: {BuiltManifestName} not found " +
+ $"under {pathToBuiltProject}. Skipping attribution manifest update.");
+ return;
+ }
+
+ var plist = new PlistDocument();
+ plist.ReadFromFile(builtManifestPath);
+ ApplyAttributionPrivacyEntries(plist.root);
+ plist.WriteToFile(builtManifestPath);
+#endif
+ }
+
+ private static string? FindBuiltManifest(string pathToBuiltProject)
+ {
+ // Unity 2019.3+ places the merged manifest here.
+ var candidate = Path.Combine(pathToBuiltProject, "UnityFramework", BuiltManifestName);
+ if (File.Exists(candidate)) return candidate;
+
+ // Fall back to a recursive search for older Unity layout variants.
+ var found = Directory.GetFiles(pathToBuiltProject, BuiltManifestName, SearchOption.AllDirectories);
+ return found.Length > 0 ? found[0] : null;
+ }
+
+#if UNITY_IOS
+ ///
+ /// Adds the attribution-specific privacy declarations to an existing
+ /// (already Unity-merged) PrivacyInfo.xcprivacy plist root.
+ /// Idempotent — safe to call on a manifest that already has these entries.
+ ///
+ internal static void ApplyAttributionPrivacyEntries(PlistElementDict root)
+ {
+ // IDFA collection constitutes tracking under Apple's definition.
+ root.SetBoolean("NSPrivacyTracking", true);
+
+ PlistElementArray dataTypes;
+ if (root.values.TryGetValue("NSPrivacyCollectedDataTypes", out var existing) &&
+ existing is PlistElementArray existingArray)
+ {
+ dataTypes = existingArray;
+ }
+ else
+ {
+ dataTypes = root.CreateArray("NSPrivacyCollectedDataTypes");
+ }
+
+ // Avoid duplicate entries if the post-processor is re-run.
+ const string advertisingType = "NSPrivacyCollectedDataTypeAdvertisingData";
+ foreach (var item in dataTypes.values)
+ {
+ if (item is PlistElementDict d &&
+ d.values.TryGetValue("NSPrivacyCollectedDataType", out var v) &&
+ v is PlistElementString s &&
+ s.value == advertisingType)
+ return;
+ }
+
+ var entry = dataTypes.AddDict();
+ entry.SetString("NSPrivacyCollectedDataType", advertisingType);
+ entry.SetBoolean("NSPrivacyCollectedDataTypeLinked", true);
+ entry.SetBoolean("NSPrivacyCollectedDataTypeTracking", true);
+ var purposes = entry.CreateArray("NSPrivacyCollectedDataTypePurposes");
+ purposes.AddString("NSPrivacyCollectedDataTypePurposeAnalytics");
+ }
+#endif
+
+ private static bool AttributionDefineEnabled()
+ {
+ var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS) ?? string.Empty;
+ foreach (var define in defines.Split(';'))
+ {
+ if (define.Trim() == iOSInfoPlistPostProcessor.AttributionDefine) return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/Packages/Audience/Editor/iOSPrivacyManifestPostProcessor.cs.meta b/src/Packages/Audience/Editor/iOSPrivacyManifestPostProcessor.cs.meta
new file mode 100644
index 000000000..e10ef7d03
--- /dev/null
+++ b/src/Packages/Audience/Editor/iOSPrivacyManifestPostProcessor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8e0d5553e0d6341f89ee2546581a1632
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.attribution.xcprivacy b/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.attribution.xcprivacy
new file mode 100644
index 000000000..72d54c0cc
--- /dev/null
+++ b/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.attribution.xcprivacy
@@ -0,0 +1,42 @@
+
+
+
+
+ NSPrivacyTracking
+
+ NSPrivacyTrackingDomains
+
+ NSPrivacyCollectedDataTypes
+
+
+
+ NSPrivacyCollectedDataType
+ NSPrivacyCollectedDataTypeDeviceID
+ NSPrivacyCollectedDataTypeLinked
+
+ NSPrivacyCollectedDataTypeTracking
+
+ NSPrivacyCollectedDataTypePurposes
+
+ NSPrivacyCollectedDataTypePurposeAnalytics
+
+
+
+
+ NSPrivacyCollectedDataType
+ NSPrivacyCollectedDataTypeAdvertisingData
+ NSPrivacyCollectedDataTypeLinked
+
+ NSPrivacyCollectedDataTypeTracking
+
+ NSPrivacyCollectedDataTypePurposes
+
+ NSPrivacyCollectedDataTypePurposeAnalytics
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+
diff --git a/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.attribution.xcprivacy.meta b/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.attribution.xcprivacy.meta
new file mode 100644
index 000000000..c90f0aef1
--- /dev/null
+++ b/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.attribution.xcprivacy.meta
@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ DefaultValueInitialized: true
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 0
+ settings: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.xcprivacy b/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.xcprivacy
new file mode 100644
index 000000000..d469414b1
--- /dev/null
+++ b/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.xcprivacy
@@ -0,0 +1,29 @@
+
+
+
+
+ NSPrivacyTracking
+
+ NSPrivacyTrackingDomains
+
+ NSPrivacyCollectedDataTypes
+
+
+
+ NSPrivacyCollectedDataType
+ NSPrivacyCollectedDataTypeDeviceID
+ NSPrivacyCollectedDataTypeLinked
+
+ NSPrivacyCollectedDataTypeTracking
+
+ NSPrivacyCollectedDataTypePurposes
+
+ NSPrivacyCollectedDataTypePurposeAnalytics
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+
diff --git a/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.xcprivacy.meta b/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.xcprivacy.meta
new file mode 100644
index 000000000..450acf685
--- /dev/null
+++ b/src/Packages/Audience/Runtime/Plugins/iOS/PrivacyInfo.xcprivacy.meta
@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ DefaultValueInitialized: true
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 1
+ settings: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant: