85

I would like to get the device IDFA. How to get this info from iOS official API ?

Rafał Sroka
  • 39,540
  • 23
  • 113
  • 143
fvisticot
  • 7,936
  • 14
  • 49
  • 79
  • 3
    Note that Apple is now advising against accessing IDFA in apps that don't have ads: https://github.com/mixpanel/mixpanel-iphone/issues/109 – Louis St-Amour Feb 02 '14 at 06:05

12 Answers12

100

First, you have to ask permission from the user to use their IDFA:

#import <AppTrackingTransparency/AppTrackingTransparency.h> 

[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
 // Tracking authorization completed. Start loading ads here. 
 }];

This permission flow will only run once, the first time it is called, even if you re-start the app and/or call it again. If you want to answer differently, you'll have to delete the app off the device or simulator completely and reinstall it. Note that iOS simulators return blanked IDFAs (all zeroes) no matter what the answer to the permission flow. See https://developer.apple.com/documentation/apptrackingtransparency for details, including how to customize the message shown to users when asking to track them. Note that many advertising SDKs have their own consent flow calls that you can use.

To actually get the IDFA once you have permission:

#import <AdSupport/ASIdentifierManager.h> 

If you would like to get it as an NSString, use:

[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]

So your code might look like this:

NSString *idfaString = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
NSLog (@"IDFA: %@", idfaString);
Zachary Drake
  • 1,356
  • 1
  • 8
  • 12
  • 13
    Remember: #import – parsley72 Dec 08 '13 at 20:50
  • @parsley72 you can use "@import AdSupport;" instead so you don't have the additional step of adding the framework. Edited the answer to include this. – vinnybad Oct 12 '15 at 04:38
  • 3
    Using Swift: `import AdSupport`, then `ASIdentifierManager.sharedManager().advertisingIdentifier` to get the IDFA! – nodebase Sep 13 '16 at 19:57
  • 1
    Note that on iOS 10, if the user has enabled Limit Ad Tracking, this IDFA will be all zeros on a physical device. (In the simulator as of Xcode 8 GM seed, it still seems to return an arbitrary IDFA.) – Zachary Drake Sep 14 '16 at 03:16
  • Note that soon (as of September 2020) you'll have to ask user permission to use IDFA. You have to use App Tracking Transparency to do this: https://developer.apple.com/documentation/apptrackingtransparency – Zachary Drake Sep 14 '20 at 16:28
  • To ask permission to get the user's IDFA, you have to launch the ATT permission flow: #import [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) { // Tracking authorization completed. Start loading ads here. }]; – Zachary Drake Feb 17 '22 at 21:39
86

You first have to check if user user has decided to opt out from ad tracking. Only if he allowed it you can use the IDFA.

You can check it by calling isAdvertisingTrackingEnabled method of ASIdentifierManager.

isAdvertisingTrackingEnabled

Check the value of this property before performing any advertising tracking. If the value is NO, use the advertising identifier only for the following purposes: frequency capping, conversion events, estimating the number of unique users, security and fraud detection, and debugging.

The following code snippet shows how to obtain a string value of IDFA.

ObjC

@import AdSupport;

- (NSString *)identifierForAdvertising {
    // Check whether advertising tracking is enabled
    if([[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]) {
        NSUUID *identifier = [[ASIdentifierManager sharedManager] advertisingIdentifier];
        return [identifier UUIDString];
    }

    // Get and return IDFA
    return nil;
}

Swift

import AdSupport

func identifierForAdvertising() -> String? {
    // Check whether advertising tracking is enabled
    guard ASIdentifierManager.shared().isAdvertisingTrackingEnabled else {
        return nil
    }

    // Get and return IDFA
    return ASIdentifierManager.shared().advertisingIdentifier.uuidString
}
Rafał Sroka
  • 39,540
  • 23
  • 113
  • 143
22

IDFA - Identifier for Advertising

isAdvertisingTrackingEnabled -> trackingAuthorizationStatus

From iOS v14 Apple deprecated isAdvertisingTrackingEnabled and moved the logic into AppTrackingTransparency Framework. Now user has to grand a permission to read idfa(in the same way as Location permission)

User can control it via:

#iOS 13
#AdSupport
#ASIdentifierManager.shared().isAdvertisingTrackingEnabled
Settings -> Privacy -> Advertising -> Limit Ad Tracking
#iOS 14
#AppTrackingTransparency
#ATTrackingManager.trackingAuthorizationStatus

#a global flag
Settings -> Privacy -> Tracking -> `Allow Apps to Request to Track` 
#or select an app from list to control every app separately 

#a local flag
Settings -> <app_name> -> Allow Tracking 

Implementation

import AppTrackingTransparency
import AdSupport
func getIDFA() -> String? {
    // Check whether advertising tracking is enabled
    if #available(iOS 14, *) {
        if ATTrackingManager.trackingAuthorizationStatus != ATTrackingManager.AuthorizationStatus.authorized  {
            return nil
        }
    } else {
        if ASIdentifierManager.shared().isAdvertisingTrackingEnabled == false {
            return nil
        }
    }

    return ASIdentifierManager.shared().advertisingIdentifier.uuidString
}
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
14

ASIdentifierManager is the official way to garner the Advertising Identification Number from a device running iOS 6+. You can use -[[ASIdentifierManager sharedManager] advertisingIdentifier]; to get it.

CodaFi
  • 43,043
  • 8
  • 107
  • 153
12

Get IDFA in Swift:

    import AdSupport

    ...

    let myIDFA: String?
    // Check if Advertising Tracking is Enabled
    if ASIdentifierManager.sharedManager().advertisingTrackingEnabled {
        // Set the IDFA
        myIDFA = ASIdentifierManager.sharedManager().advertisingIdentifier.UUIDString
    } else {
        myIDFA = nil
    }
Amr Hossam
  • 2,313
  • 1
  • 22
  • 23
7

Beginning in iOS 10, when a user enables “Limit Ad Tracking,” the OS will send along the advertising identifier with a new value of “00000000-0000-0000-0000-000000000000.”

As per this article: https://fpf.org/2016/08/02/ios-10-feature-stronger-limit-ad-tracking/

Vlad
  • 5,727
  • 3
  • 38
  • 59
6

Here's a commented helper class in Swift that will give you a nil object for the identifier if the user has turned advertisement tracking off:

import AdSupport

class IDFA {
    // MARK: - Stored Type Properties
    static let shared = IDFA()

    // MARK: - Computed Instance Properties
    /// Returns `true` if the user has turned off advertisement tracking, else `false`.
    var limited: Bool {
        return !ASIdentifierManager.shared().isAdvertisingTrackingEnabled
    }

    /// Returns the identifier if the user has turned advertisement tracking on, else `nil`.
    var identifier: String? {
        guard !limited else { return nil }
        return ASIdentifierManager.shared().advertisingIdentifier.uuidString
    }
}

Just add it to your project (for example in a file named IDFA.swift) and link the AdSupport.framework in your target via the "Linked Frameworks and Libraries" section in the General settings tab.

Then you can use it like this:

if let identifier = IDFA.shared.identifier {
    // use the identifier
} else {
    // put any fallback logic in here
}
Jeehut
  • 20,202
  • 8
  • 59
  • 80
  • cool, but you don't need to use IDFA as a singleton, ASIdentifierManager is already a singleton, so, just make the var as class var to use them directly – busta117 Nov 21 '18 at 01:30
6

Swift 3 & 4

var IDFA = String()
if ASIdentifierManager.shared().isAdvertisingTrackingEnabled {
            IDFA = ASIdentifierManager.shared().advertisingIdentifier
}
Oscar Falmer
  • 1,771
  • 1
  • 24
  • 38
4

Please pay attention that in iOS 14, ASIdentifierManager.shared().isAdvertisingTrackingEnabled is deprecated. please use ATTrackingManager.trackingAuthorizationStatus == .authorized instead.

import AdSupport
import AppTrackingTransparency

extension ASIdentifierManager {
    //NOTE: if the user has enabled Limit Ad Tracking, this IDFA will be all zeros on a physical device
    static var identifierForAdvertising: String {

        // Check whether advertising tracking is enabled
        if #available(iOS 14, *) {
            guard ATTrackingManager.trackingAuthorizationStatus == .authorized else {
                return ""
            }
        } else {
            guard ASIdentifierManager.shared().isAdvertisingTrackingEnabled else {
                return ""
            }
        }
            
        // Get and return IDFA
        return ASIdentifierManager.shared().advertisingIdentifier.uuidString
    }
}
yonivav
  • 994
  • 11
  • 18
2

A nicer approach to get the IDFA or nil if tracking is disabled via iOS Setting is using a (private) extension:

import AdSupport

class YourClass {

    func printIDFA() {
        print(ASIdentifierManager.shared().advertisingIdentifierIfPresent)
    }
}

private extension ASIdentifierManager {

    /// IDFA or nil if ad tracking is disabled via iOS system settings
    var advertisingIdentifierIfPresent: String? {
        if isAdvertisingTrackingEnabled {
            return advertisingIdentifier.uuidString
        }

        return nil 
    }        
}
henrik-dmg
  • 1,448
  • 16
  • 23
Jochen Holzer
  • 1,598
  • 19
  • 25
1

Just to extend Amro's Swift answer, here's similar code wrapped in a method:

import AdSupport

...

func provideIdentifierForAdvertisingIfAvailable() -> String? {
    if ASIdentifierManager.sharedManager().advertisingTrackingEnabled {
      return ASIdentifierManager.sharedManager().advertisingIdentifier?.UUIDString ?? nil
    } else {
      return nil
    }
  }
worthbak
  • 335
  • 3
  • 8
0

Swift 5 with encapsulation:

import AdSupport

struct ID{
    static var advertising: String? {
         // Firstly, Check whether advertising tracking is enabled
         guard ASIdentifierManager.shared().isAdvertisingTrackingEnabled else {
              return nil
         }
         // Then, Get and return IDFA
         return ASIdentifierManager.shared().advertisingIdentifier.uuidString
     }
}
black_pearl
  • 2,549
  • 1
  • 23
  • 36