Skip to main content

App Tracking Transparency (ATT)

This guide provides comprehensive instructions for implementing Apple's App Tracking Transparency (ATT) framework with the Trackier iOS SDK. ATT is required for iOS 14.5+ apps that want to access the Identifier for Advertisers (IDFA) for accurate attribution and tracking.

Overview

App Tracking Transparency (ATT) is Apple's privacy framework that requires apps to request user permission before accessing the IDFA. This is crucial for accurate attribution and tracking on iOS 14.5 and later.

Prerequisites

  • iOS 14.5 or later
  • Xcode 12.0 or later
  • Trackier iOS SDK installed
  • Access to your app's Info.plist file

Implementation

Step 1: Add Permission Description

Add the following key-value pair to your Info.plist to describe why your app needs tracking permission:

<key>NSUserTrackingUsageDescription</key>
<string>We use tracking to personalize your experience and improve our services.</string>

Step 2: Create AppTrackingService Class

Create a dedicated service class to handle ATT permissions. This provides better organization and reusability:

AppTrackingService.swift
import Foundation
import AppTrackingTransparency
import AdSupport

class AppTrackingService: ObservableObject {
@Published var trackingStatus: ATTrackingManager.AuthorizationStatus = .notDetermined

static let shared = AppTrackingService()

private init() {
updateTrackingStatus()
}

func updateTrackingStatus() {
trackingStatus = ATTrackingManager.trackingAuthorizationStatus
}

func requestTrackingPermission() {
// Check if we can request permission
guard ATTrackingManager.trackingAuthorizationStatus == .notDetermined else {
print("ATT permission already determined: \(ATTrackingManager.trackingAuthorizationStatus)")
return
}

ATTrackingManager.requestTrackingAuthorization { [weak self] status in
DispatchQueue.main.async {
self?.trackingStatus = status
self?.handleTrackingPermissionResponse(status: status)
}
}
}

private func handleTrackingPermissionResponse(status: ATTrackingManager.AuthorizationStatus) {
switch status {
case .authorized:
print("App Tracking Permission: Authorized")
// User granted permission, tracking is now allowed
// The Trackier SDK will automatically start tracking
// You can now access IDFA if needed
if let idfa = self.idfa {
print("IDFA: \(idfa)")
}

case .denied:
print("App Tracking Permission: Denied")
// User denied permission, tracking is not allowed
// The Trackier SDK will handle this gracefully

case .restricted:
print("App Tracking Permission: Restricted")
// Tracking is restricted (e.g., parental controls)

case .notDetermined:
print("App Tracking Permission: Not Determined")
// Permission hasn't been requested yet

@unknown default:
print("App Tracking Permission: Unknown status")
}
}

var canTrack: Bool {
return trackingStatus == .authorized
}

var idfa: String? {
guard canTrack else { return nil }
return ASIdentifierManager.shared().advertisingIdentifier.uuidString
}
}

Step 3: Update Your App's Main File

note

Important: Always include TrackierSDK.waitForATTUserAuthorization(timeoutInterval: 20) before initializing the SDK. This ensures the SDK waits for the user's ATT decision before starting tracking, which is required for accurate attribution on iOS 14.5+. You can adjust the timeout value (20 seconds) according to your use case or logic.

Update your main app file (e.g., AppDelegate.swift or App.swift) to integrate ATT with the Trackier SDK:

AppDelegate.swift
import UIKit
import trackier_ios_sdk

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
private let trackingService = AppTrackingService.shared

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {

// Initialize Trackier SDK with ATT support
initializeTrackierSDK()

// Request tracking permission after a short delay
requestTrackingPermissionIfNeeded()

return true
}

private func initializeTrackierSDK() {
// Create SDK configuration
let config = TrackierSDKConfig(
appToken: "YOUR_SDK_TOKEN_HERE", // Replace with your actual SDK token
env: TrackierSDKConfig.ENV_DEVELOPMENT
)

// Wait for ATT authorization before initializing SDK
TrackierSDK.waitForATTUserAuthorization(timeoutInterval: 20)

// Initialize the SDK
TrackierSDK.initialize(config: config)

// Configure conversion values after initialization
TrackierSDK.updatePostbackConversion(fineValue: 0, coarseValue: "low")
}

private func requestTrackingPermissionIfNeeded() {
// Check if ATT is available (iOS 14.5+)
if #available(iOS 14.5, *) {
// Request tracking permission after a short delay to ensure the app is fully loaded
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
if self.trackingService.trackingStatus == .notDetermined {
self.trackingService.requestTrackingPermission()
}
}
} else {
print("ATT not available on this iOS version")
}
}
}

Step 4: For SwiftUI Apps

If you're using SwiftUI, update your main app file:

YourApp.swift
import SwiftUI
import trackier_ios_sdk

@main
struct YourApp: App {
@StateObject private var trackingService = AppTrackingService.shared

init() {
initializeTrackierSDK()
}

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(trackingService)
.onAppear {
requestTrackingPermissionIfNeeded()
}
}
}

private func initializeTrackierSDK() {
let config = TrackierSDKConfig(
appToken: "YOUR_SDK_TOKEN_HERE", // Replace with your actual SDK token
env: TrackierSDKConfig.ENV_DEVELOPMENT
)

// Wait for ATT authorization before initializing SDK
TrackierSDK.waitForATTUserAuthorization(timeoutInterval: 20)

// Initialize the SDK
TrackierSDK.initialize(config: config)

// Configure conversion values after initialization
TrackierSDK.updatePostbackConversion(fineValue: 0, coarseValue: "low")
}

private func requestTrackingPermissionIfNeeded() {
// Check if ATT is available (iOS 14.5+)
if #available(iOS 14.5, *) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
if trackingService.trackingStatus == .notDetermined {
trackingService.requestTrackingPermission()
}
}
} else {
print("ATT not available on this iOS version")
}
}
}

Key Features

  • waitForATTUserAuthorization(timeoutInterval: 20): This method waits for the user to respond to the ATT prompt before initializing the SDK. The timeout can be adjusted based on your app's needs.
  • Automatic Status Handling: The service automatically handles all ATT status responses.
  • IDFA Access: Provides easy access to IDFA when permission is granted.
  • ObservableObject: Integrates seamlessly with SwiftUI for reactive UI updates.
warning

Always replace "YOUR_SDK_TOKEN_HERE" with your actual SDK token from the Trackier Panel. Using an incorrect token will cause attribution issues.

Visual Examples

ATT Permission Dialog:

ATT Permission Dialog

IDFA Console Logs:


IDFA Access


IDFA Panel in Trackier Dashboard: When tracking is properly configured with ATT, you can see the IDFA details in the Trackier panel for installs and events:

IDFA Panel Details

This panel shows the IDFA information when users grant tracking permission, allowing for accurate attribution and detailed tracking analytics.

ATT Status Values

StatusDescriptionSDK Behavior
.authorizedUser granted permissionFull tracking enabled, IDFA available
.deniedUser denied permissionLimited tracking, no IDFA
.restrictedSystem restricted (parental controls)Limited tracking, no IDFA
.notDeterminedPermission not requested yetWait for user decision

Best Practices

  • Timing: Request permission after app launch (1-2 second delay)
  • User Experience: Explain why tracking is needed before requesting permission
  • Timeout Configuration: Adjust timeout based on your app's flow (default 20 seconds)
  • Status Monitoring: Monitor tracking status changes and update UI accordingly
  • Check Status First: Always check if permission has already been determined before requesting
  • Handle All Cases: Implement proper handling for all ATT status values
  • iOS Version Check: Always check if ATT is available before using it

Troubleshooting

Common Issues

ATT Permission Not Requested

  • Ensure NSUserTrackingUsageDescription is added to Info.plist
  • Check that the app targets iOS 14.5 or later
  • Verify the permission request is called after app launch

IDFA Not Available

  • Check if user granted permission (status should be .authorized)
  • Ensure the device supports IDFA (not available on simulator)
  • Verify the app is not restricted by parental controls

SDK Initialization Issues

  • Make sure waitForATTUserAuthorization is called before SDK initialization
  • Check that the timeout value is appropriate for your app flow
  • Verify the SDK token is correct

Debug Tips

// Check current tracking status
let status = ATTrackingManager.trackingAuthorizationStatus
print("Current ATT Status: \(status)")

// Check if IDFA is available
if let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString {
print("IDFA: \(idfa)")
} else {
print("IDFA not available")
}

Support

For technical support and questions:


This guide provides comprehensive implementation of App Tracking Transparency with the Trackier iOS SDK, ensuring compliance with Apple's privacy requirements while maintaining accurate attribution and tracking capabilities.