Skip to main content
This guide covers using the Identifier for Advertisers (IDFA) with the Permutive SDK, including App Tracking Transparency requirements and privacy best practices.

Important: IDFA Recommendation

Permutive recommends against using IDFA for identity. Apple’s App Tracking Transparency (ATT) requirements significantly limit IDFA availability and utility. Consider using identifierForVendor or hashed email addresses instead.

Why Not IDFA?

  1. Low opt-in rates: Most users deny tracking permission
  2. Extra implementation: Requires ATT framework integration
  3. App Store compliance: Must justify IDFA usage in App Store Connect
  4. Limited utility: Only available when user explicitly permits
  5. Not available on tvOS: ATT is not supported on tvOS

1. Identifier for Vendor (IDFV)

A consistent identifier across your apps from the same vendor:
import UIKit
import Permutive_iOS

func setVendorIdentity() {
    guard let idfv = UIDevice.current.identifierForVendor?.uuidString else {
        return
    }

    let alias = Alias(tag: "idfv", identity: idfv, priority: 2)
    try? Permutive.shared.setIdentities(aliases: [alias])
}
Benefits:
  • No user permission required
  • Consistent across app installs (until uninstall)
  • Available on both iOS and tvOS
  • No App Store justification needed

2. Hashed Email Address

The most reliable cross-device identifier:
import CryptoKit
import Permutive_iOS

func setEmailIdentity(email: String) {
    let normalized = email.trimmingCharacters(in: .whitespaces).lowercased()
    let data = Data(normalized.utf8)
    let hash = SHA256.hash(data: data)
    let emailHash = hash.compactMap { String(format: "%02x", $0) }.joined()

    let alias = Alias(tag: "email_sha256", identity: emailHash, priority: 0)
    try? Permutive.shared.setIdentities(aliases: [alias])
}
Benefits:
  • Works across devices and platforms
  • Highest priority for identity resolution
  • No Apple framework dependencies
  • User provided and expected

3. Internal User ID

Your system’s user identifier:
func setUserIdentity(userId: String) {
    let alias = Alias(tag: "internal_id", identity: userId, priority: 1)
    try? Permutive.shared.setIdentities(aliases: [alias])
}

App Tracking Transparency

If you still need IDFA, follow these steps:

1. Add Usage Description

Add to your Info.plist:
<key>NSUserTrackingUsageDescription</key>
<string>We use this identifier to personalize your ad experience.</string>

2. Request Permission

import AppTrackingTransparency
import AdSupport
import Permutive_iOS

class TrackingPermissionManager {

    func requestTrackingPermission() {
        // Only available on iOS 14+
        if #available(iOS 14, *) {
            ATTrackingManager.requestTrackingAuthorization { status in
                switch status {
                case .authorized:
                    self.setIDFAIdentity()
                case .denied:
                    print("User denied tracking")
                case .restricted:
                    print("Tracking restricted")
                case .notDetermined:
                    print("Not determined")
                @unknown default:
                    break
                }
            }
        } else {
            // iOS 13 and earlier - no ATT required
            setIDFAIdentity()
        }
    }

    private func setIDFAIdentity() {
        let idfa = ASIdentifierManager.shared().advertisingIdentifier

        // Check if IDFA is valid (not all zeros)
        guard idfa != UUID(uuidString: "00000000-0000-0000-0000-000000000000") else {
            print("IDFA not available (tracking denied or restricted)")
            return
        }

        do {
            try Permutive.shared.setIdentityForIDFA(idfa)
            print("IDFA set successfully")
        } catch {
            print("Failed to set IDFA: \(error)")
        }
    }
}

3. Check Status Before Requesting

func checkAndRequestTracking() {
    if #available(iOS 14, *) {
        let status = ATTrackingManager.trackingAuthorizationStatus

        switch status {
        case .notDetermined:
            // Can request permission
            requestTrackingPermission()

        case .authorized:
            // Already authorized
            setIDFAIdentity()

        case .denied, .restricted:
            // Cannot use IDFA
            useAlternativeIdentity()

        @unknown default:
            break
        }
    }
}

4. When to Request

Don’t request tracking permission immediately on app launch. Wait for an appropriate moment when the user understands the value.
// Good: Request after user has engaged with the app
func onFirstContentView() {
    // User has started using the app
    requestTrackingPermission()
}

// Good: Request when user is about to see ads
func onPrepareToPresentAds() {
    requestTrackingPermission()
}

// Bad: Requesting immediately on launch
func applicationDidFinishLaunching() {
    // Don't do this - user hasn't understood the app yet
    // requestTrackingPermission()
}

Using setIdentityForIDFA

The SDK provides a dedicated method for IDFA:
do {
    try Permutive.shared.setIdentityForIDFA(idfa)
} catch {
    // IDFA was invalid (all zeros) or otherwise unusable
    print("setIdentityForIDFA failed: \(error)")
}
This method:
  • Sets an alias with the reserved tag "idfa"
  • Validates the IDFA is not all zeros
  • Throws an error if IDFA is invalid

Apple Privacy Information

When submitting to the App Store, you must declare data collection. For apps using Permutive:

Without IDFA

If you’re NOT using IDFA, Permutive’s SDK data collection is:
  • Identifiers: Device ID (vendor identifier if used)
  • Usage Data: Product interaction
  • Purpose: Analytics, advertising

With IDFA

If you ARE using IDFA, also declare:
  • Identifiers: Device ID (IDFA)
  • Purpose: Third-party advertising, tracking
For complete privacy information, see Apple’s App Store data collection policies.

tvOS Considerations

tvOS Note: App Tracking Transparency and IDFA are not available on tvOS. Use identifierForVendor or hashed email as primary identifiers on tvOS.
#if os(tvOS)
// tvOS - use vendor identifier
if let idfv = UIDevice.current.identifierForVendor?.uuidString {
    let alias = Alias(tag: "idfv", identity: idfv, priority: 2)
    try? Permutive.shared.setIdentities(aliases: [alias])
}
#else
// iOS - can request IDFA if needed
requestTrackingPermission()
#endif

Best Practices

  • Use identifierForVendor as a reliable alternative
  • Use hashed email for cross-device identity
  • Request ATT permission at an appropriate time
  • Explain the value to users before requesting
  • Handle all authorization statuses gracefully
  • Have fallback identifiers when IDFA unavailable

Troubleshooting

Problem: IDFA call fails with error.Cause: IDFA is all zeros (tracking denied/restricted).Solution: Check authorization status first and use alternative identifiers:
if ATTrackingManager.trackingAuthorizationStatus == .authorized {
    try Permutive.shared.setIdentityForIDFA(idfa)
} else {
    setAlternativeIdentity()
}
Problem: requestTrackingAuthorization doesn’t show prompt.Possible Causes:
  • Missing NSUserTrackingUsageDescription in Info.plist
  • User already responded (check status first)
  • Running on iOS 13 or earlier
  • Running on simulator (may behave differently)
Problem: App Store rejects app for tracking without permission.Solution: Ensure you:
  • Request ATT permission before accessing IDFA
  • Have clear NSUserTrackingUsageDescription
  • Accurately declare data usage in App Store Connect