Server-to-Server (S2S) Integration Guide

Note: Server-to-server integrations are only available by request. Talk to your Singular Customer Service Manager or Singular Support.

 

As an alternative to the Singular SDK, which has to be embedded within your apps, Singular also provides a REST API that can be used to build a full integration that runs from your own server.

This guide explains how to build a basic S2S integration with Singular and implement various optional features.

For a full list of the S2S API endpoints, their parameters, and sample calls, see the S2S Endpoint Reference.

Basic Integration

The most basic integration with Singular involves letting Singular know when there is a new session - in other words, when the app is opened.

To notify Singular about a user session, call the Session Notification Endpoint.

Session notifications allow Singular to do several things:

  • If it's the first session for the app on the specific device, Singular recognizes a new install and triggers the install attribution process.
  • If the session qualifies as a re-engagement session, Singular triggers the re-engagement attribution process (learn more in the Re-engagement FAQ).
  • Otherwise, Singular marks it as a session, which is used to track user activity and retention.

The Session Notification endpoint has some required parameters. For help obtaining all the necessary data to report a session, see Reference: Retrieving the iOS Install Receipt and Reference: Retrieving Device Identifiers and Session Data.

Tip: When you collect the data to report a session, be sure to wait for asynchronous functions to return and handle various edge cases. This is a common issue that can cause missing data and partial attribution.

Collecting and Sending the App Set ID (Required for Android 12+)

The App Set ID or ASID is a new privacy-friendly ID used in Android 12+ devices. The App Set ID is shared by all apps on a device that have been published in the Google Play store by the same developer.

Add the App Set ID as a parameter to the session call and every event call, similarly to how you would send the GAID.

To collect the App Set ID, use the following code in your app:

Context context = getApplicationContext();
AppSetIdClient client = AppSet.getClient(context);
Task<AppSetIdInfo> task = client.getAppSetIdInfo();

task.addOnSuccessListener(new OnSuccessListener<AppSetIdInfo>() {
    @Override
    public void onSuccess(AppSetIdInfo info) {
        // Determine current scope of app set ID.
        int scope = info.getScope();

        // Read app set ID value, which uses version 4 of the
        // universally unique identifier (UUID) format.
        String id = info.getId();
    }
});

Important: Sending the Google Play Install Referrer (Android)

The install referrer contains information about who sent a user to the Google Play Store. When the install referrer is available to Singular, it provides the most accurate way to attribute installs. Retrieve this value and pass it along to Singular on the first session notification call. It is required for some important Singular features, such as receiving Facebook data in our User-Level Exports, sharing it with Data Destinations, and sending postbacks.

Google Play collects referrer information when a user arrives at the store. If the user later installs the app they were directed to, Google Play makes the information available to the app. For more information, see Google's developer documentation.

To share the install referrer with Singular:

  1. When the app is opened for the first time, retrieve the install referrer using the Play Install Referrer API.
  2. Report a session to Singular using the Session Notification endpoint including the parameter install_ref. This parameter is JSON-encoded and has the following attributes:

    Attribute Description
    referrer The referrer value as retrieved from the Play Install Referrer API. This is a JSON object, so make sure to encode it as a string.
    referrer_source Specify "service".
    clickTimestampSeconds The click timestamp as received from the Play Install Referrer API (e.g., "1550420123").
    installBeginTimestampSeconds
    The time that the install started, as received from the Play Install Referrer API.
    current_device_time The time in the current device, in milliseconds (e.g., "1550420454906").

The following is sample code for reporting the install referrer event:

Python HTTP
import requests
import json

SDK_KEY = '<sdk key from developer tools > sdk keys'
LAUNCH_URL = 'https://s2s.singular.net/api/v1/launch'

referrer_values = {
      "referrer": "tracking_id%3D123456789&utm_source%3Dmdotm%26utm_medium%3Dbanner%26utm_campaign%3Dcampaign",
      "referrer_source" : "service",
      "clickTimestampSeconds" : 1550420123,
      "installBeginTimestampSeconds" : 1550420123,
      "current_device_time" : 1550420454906
    }

referrer_values = json.dumps(referrer_values, separators=(',',':')) params = { 'a': SDK_KEY, 'p': 'Android', 'i': 'com.singular.app', 'ip': '10.1.2.3', 've': '9.2', 'ma': 'samsung', 'mo': 'SM-G935F', 'lc': 'en_US', 'aifa': '8ecd7512-2864-440c-93f3-a3cabe62525b', 'andi': 'fc8d449516de0dfb', 'utime': 1483228800, 'dnt': 0, 'install':'true', 'n': 'MyCoolApp', 'c': 'wifi', 'cn': 'Comcast', 'bd': 'Build/13D15', 'fcm':'bk3RNwTe3H0CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1', 'app_v':'1.2.3', 'openuri':'myapp%3A%2F%2Fhome%2Fpage%3Fqueryparam1%3Dvalue1', 'ddl_enabled':'false', 'install_source': 'com.android.vending', 'install_time': 1510040127, 'update_time': 1510090877, 'custom_user_id': '123456789abcd', 'install_ref' : referrer_values } result = requests.get(LAUNCH_URL, params=params) print result.json()

Optional: Sending the User ID

When you notify Singular about a new session, you can add the user ID. This can be a username, email address, randomly generated string, or whichever identifier your app uses as a user ID. Singular will use the user ID in user-level data exports as well as internal BI postbacks (if you configure any).

To send the user ID, add the "custom_user_id" parameter when you call the Session Notification Endpoint.

For example:

Python HTTP cURL
import requests
 import json

SDK_KEY = '<sdk key from developer tools > sdk keys'
LAUNCH_URL = 'https://s2s.singular.net/api/v1/launch'

params = {
  'a': SDK_KEY,
  'p': 'Android',
  'i': 'com.singular.app',
  'ip': '10.1.2.3',
  've': '9.2',
  'ma': 'samsung',
  'mo': 'SM-G935F',
  'lc': 'en_US',
  'aifa': '8ecd7512-2864-440c-93f3-a3cabe62525b',
  'andi': 'fc8d449516de0dfb',
  'utime': 1483228800,
  'dnt': 0,
  'install':'true',
  'n': 'MyCoolApp',
  'c': 'wifi',
  'cn': 'Comcast',
  'bd': 'Build/13D15',
  'fcm':'bk3RNwTe3H0CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1',
  'app_v':'1.2.3',
  'openuri':'myapp%3A%2F%2Fhome%2Fpage%3Fqueryparam1%3Dvalue1',
  'ddl_enabled':'false',
  'install_source': 'com.android.vending',
  'install_time': 1510040127,
  'update_time': 1510090877,
  'custom_user_id': 'player_id_1234'
}

result = requests.get(LAUNCH_URL, params=params)
print result.json()

Additional Attribution Handling

Attribution for Apple Search Ads Campaigns (iOS)

Apple Search Ads is considered a Self-Attributing Network (SAN).  As of iOS 14.3, the Apple Search Ads integration is supported through two iOS frameworks:

We recommend that both the iAd and AdServices frameworks are implemented until the iAd framework is deprecated at a future date.  Since AdServices is still a new Apple service, Singular will utilize both services but prioritize AdServices over iAd signals for attribution and reporting. 

For more information, see our Apple Search Ads integration documentation.

Implementing Apple Search Ads via iAd (iOS 14.2 and below)

1. Retrieving the Attribution Data:

To retrieve the attribution data, use the Apple Search Ads iAd API. Calling requestAttributionDetails(_:): returns a JSON object containing the attribution data.

For example:

Objective-C
#import <iAd/iAd.h>

  Class ADClientClass = NSClassFromString(@"ADClient");

  if (ADClientClass) {
      id sharedClient = [ADClientClass performSelector:@selector(sharedClient)];
      
      if ([sharedClient respondsToSelector:@selector(requestAttributionDetailsWithBlock:)]) {
          [sharedClient requestAttributionDetailsWithBlock:^(NSDictionary *attributionDetails, NSError *error) {
              if (attributionDetails && attributionDetails.count > 0) {
                  // REPORT attributionDetails FROM YOUR APP TO YOUR SERVER
              }
          }];
      }
  }
Warning: Often, users who click on a Search Ads ad download and open the app immediately. If there is any latency in communications, an MMP such as Singular may not be able to receive and process the ad click in time before the app is opened and calls the Search Ads Attribution API. To prevent this, Apple recommends:
  1. Setting a delay of a few seconds before retrieving attribution data.
  2. Implementing retry logic if the response is False or an error code (0, 2, 3). Call the Apple Attribution API again 2 seconds later.

2. Sending the Attribution Data to Singular:

To share the attribution data with Singular, use the Event Notification endpoint to report an event with the reserved event name __iAd_Attribution__. Pass the JSON object you retrieved in the previous step as the value of the parameter, as in the example below.

Python HTTP
import requests
import json

SDK_KEY = ' sdk keys'
EVENT_URL = 'https://s2s.singular.net/api/v1/evt'

# !!! REPLACE WITH COLLECTED VALUE FROM APP !!!
apple_attribution_data = {
  u'Version3.1': {
      u'iad-adgroup-id': u'1234567',
      u'iad-adgroup-name': u'Ad Group Name',
      u'iad-attribution': u'true',
      u'iad-campaign-id': u'1234567',
      u'iad-campaign-name': u'Search Campaign',
      u'iad-click-date': u'2016-05-21T12:19:31Z',
      u'iad-conversion-date': u'2016-05-21T12:19:41Z',
      u'iad-keyword': u'ballon',
      u'iad-lineitem-id': u'1234567',
      u'iad-lineitem-name': u'Line Item Name',
      u'iad-org-name': u'Cool Company',
      u'iad-purchase-date': u'2016-05-21T12:19:41Z'
  }
}

params = {
  'n': '__iAd_Attribution__',
  'e': json.dumps(apple_attribution_data),
  'a': SDK_KEY,
  'p': 'iOS',
  'i': 'com.singular.app',
  'ip': '10.1.2.3',
  've': '9.2',
  'mo': 'iPhone9%2C4',
  'lc': 'en_US',
  'idfa': '8ECD7512-2864-440C-93F3-A3CABE62525B',
  'idfv': '38548D9F-3F73-4D4B-8545-9A920CC89191',
  'utime': 1483228800
}

result = requests.get(EVENT_URL, params=params)
print result.json()

Notes:

  • For iOS 13+, you have to send the __iAd_Attribution__ event immediately after the first session after install or re-install. Otherwise, the Apple Search Ads data will not be considered for attribution.
  • In iOS 14+, Apple Search Ads attribution responses are only available under certain conditions and not available if AppTrackingTransparency status is ATTrackingManager.AuthorizationStatus.denied

Implementing Apple Search Ads via AdServices (iOS 14.3 and above)

1. Retrieving the attribution token:

Retrieve the attribution token using attributionToken() as soon the app initializes for the first time after an install or re-install. 

For example:

Objective-C
#import <AdServices/AdServices.h> 

NSError *error = nil;
Class AAAttributionClass = NSClassFromString(@"AAAttribution");
if (AAAttributionClass) {
NSString *attributionToken = [AAAttributionClass attributionTokenWithError:&error];
if (!error && attributionToken) {
// Handle attributionToken
}
}

Notes:

  • The attribution token is generated on the device.
  • After generating, the token is cached for 5 minutes on the device.  After 5 minutes, a new token is generated if attributionToken() is called.
  • The generated token is valid for 24 hours.

2. Send the attribution token to Singular:

URL encode the token and send the token to Singular via the session notification endpoint, appended to the &attribution_token= parameter.   This token should be sent on the first session after every install and re-install to enable Singular to track Apple Search Ads downloads and re-downloads.   

Tracking Events

Singular can collect data about in-app events to help analyze the performance of your marketing campaigns. Events can include any user interaction from logins and registrations to leveling up in a gaming app.

Before you implement an SDK/S2S integration with Singular, you should have a list of the events your organization wants to track (see Defining In-App Events).

To notify Singular when an event occurs in your app, call the Event Notification endpoint. The event name you include in the call is how the event will be identified in Singular reports, exports, and postbacks.

Notes:

  • We highly recommend passing event names and other attributes in English for compatibility with any third-party partners and analytics solutions you may want to use.
  • Event names are limited to 32 ASCII characters. For non-ASCII characters, the limit is 32 bytes once converted to UTF-8.
  • Event attributes and values are limited to 500 ASCII characters.

Tracking Revenue

Singular can collect data about revenue gained through the app to help analyze the performance and ROI of your campaigns. Singular will make the data available to you in reports, log export, and postbacks.

To track revenue events, use the same Event Notification endpoint that you use for all events, but add the following information:

  • is_revenue_event=true: This marks the event as a revenue event. You can skip this parameter if the event name is __iap__ or the amount is larger than zero.
  • Purchase receipt: This is an object returned from Android's or iOS's In-App Purchase (IAP) process. We highly recommend passing it along to Singular to give Singular full details about the transaction and enrich your Singular reports with data.
  • Purchase signature (Android only): We highly recommend passing this bit of data along to Singular to validate the transaction and fight in-app fraud.
  • Revenue amount (e.g., "amt=1.99").
  • Currency (use the ISO 4217 currency code, e.g. "cur=USD").

Retrieving the Purchase Receipt

After a revenue event occurs, here's how to get the purchase receipt so you can send it to Singular:

  • In Android: Google Play provides an API to retrieve the purchase receipt ("In-App Purchase Data") and the purchase signature ("In-App Data Signature"). Use the getBuyIntent() method.
  • In iOS: Use Apple's In-App Purchases API as shown in the example below (for more information, see Apple In-App Purchases API).
Objective-C
// SKPaymentTransactionObserver
  + (void)paymentQueue:(id)queue updatedTransactions:(NSArray *)skTransactions {
     NSString *transactionReceipt = nil;

     if ([skTransaction respondsToSelector:@selector(transactionReceipt)]) {
        NSData *transactionReceiptRaw = [skTransaction performSelector:@selector(transactionReceipt)];
        if (transactionReceiptRaw) {
           transactionReceipt = [ApUtils base64Encode:transactionReceiptRaw];
        }
     }
  }

Sample Custom Revenue Event

Python HTTP cURL
import requests
import json SDK_KEY = ' sdk keys' EVENT_URL = 'https://s2s.singular.net/api/v1/evt' params = { 'a': SDK_KEY, 'p': 'Android', 'i': 'com.singular.app', 'ip': '10.1.2.3', 've': '9.2', 'ma': 'samsung', 'mo': 'SM-G935F', 'lc': 'en_US',
'bd': 'Build/13D15', 'aifa': '8ecd7512-2864-440c-93f3-a3cabe62525b', 'utime': 1483228800, 'n': 'RevenueEventName',
'amt': '2.50', 'cur': 'USD',
'is_revenue_event': 'true',
'purchase_receipt': {'orderId"':'GPA.1234',
'packageName':'com.example',
'productId':'com.example.product',
'purchaseTime':1417113074914,
'purchaseState':0,
'purchaseToken':'hakfcimbk... pM'},
'receipt_signature': 'TyVJfHg8OAoW7W4wuJt...5agEDMnNXvhfrw==',
'purchase_product_id': 'com.example.product',
'purchase_transaction_id': 'GPA.1234-1234-1234-12345' } result = requests.get(EVENT_URL, params=params) print result.json()

Supporting Deep Links

Deep links are links that lead into specific content inside an app. When a user clicks a deep link on a device that has the app installed, the app opens and shows a specific product or experience.

Singular tracking links can include deep linking as well as deferred deep linking (see our Deep Linking FAQ and the Singular Links FAQ for more information).

Deep Linking Prerequisites

For iOS:

For Android:

Supporting Deep Links

Whenever your app is opened through a deep link, add the URL when you report the session to Singular by using the openuri parameter. This is required when using Singular Links.

Enabling Deferred Deep Links

When the app is opened for the first time since the install, enable the deferred deep linking flow by adding the following parameters when you report the session to Singular:

  • install=true
  • ddl_enabled=true

Singular looks to see if the app was installed through a tracking link that included a deferred deep link. If it was, the call returns the following values:

  • deferred_deeplink - the deep link address. This is what you need to parse to show the users the right product or experience.
  • deferred_passthrough - any passthrough parameters added to the deep link.

Sample Session Notification Call with Deferred Deep Link Support

Python
import requests
    import json

    SDK_KEY = ' sdk keys'
    LAUNCH_URL = 'https://s2s.singular.net/api/v1/launch'

    params = {
        'a': SDK_KEY,
        'p': 'iOS',
        'i': '162738612',
        'ip': '10.1.2.3',
        've': '9.2',
        'mo': 'iPhone9%2C4',
        'lc': 'en_US',
        'idfa': '8ECD7512-2864-440C-93F3-A3CABE62525B',
        'idfv': '38548D9F-3F73-4D4B-8545-9A920CC89191',
        'utime': 1483228800,
        'dnt': 0,
        'n': 'MyCoolApp',
        'c': 'wifi',
        'cn': 'Comcast',
        'bd': 'Build/13D15',
        'openuri':'https://myapp.sng.link/A59c0/nha7?_dl=myapp%3A%2F%2Fdeeplink&_ddl=myapp%3A%2F%2Fdeferred-deeplink&_p=passthroughvalue',
        'install':'true',
        'ddl_enabled':'true'
    }

    result = requests.get(LAUNCH_URL, params=params)
    print result.json()

Sample Response

{
  "deferred_deeplink":"myapp://deferred-deeplink",
  "status":"ok",
  "deferred_passthrough":"passthroughvalue"
}

Supporting Dynamic Passthrough Parameters

Singular tracking links can include dynamic passthrough parameters (learn more). If your organization has set up dynamic passthrough parameters for a link, the deep link URL includes the _p parameter followed by a URL-encoded JSON value or an unstructured string which you can use to show the user the appropriate content or experience.

Advanced Options

The Singular S2S integration supports the following advanced features. They are implemented using the same API endpoints described above but with special parameters and requirements.

Tracking Uninstalls

Singular can track uninstalls using the device's Silent Push Notifications. To enable it, you will need to send the device's push token to the Singular server along with every session notification.

Tracking Uninstalls in Android

To enable uninstall tracking in Android, first retrieve the FCM token from the app by calling FirebaseInstanceId.getInstance().getToken(). This method returns null if the token has not yet been generated. For more information, see the Google Firebase Documentation.

Then pass the device token in the fcm parameter when reporting the session to Singular, as in the following example:

Python HTTP cURL
import requests
import json

SDK_KEY = ' sdk keys'
LAUNCH_URL = 'https://s2s.singular.net/api/v1/launch'

params = {
  'a': SDK_KEY,
  'p': 'Android',
  'i': 'com.singular.app',
  'ip': '10.1.2.3',
  've': '9.2',
  'ma': 'samsung',
  'mo': 'SM-G935F',
  'lc': 'en_US',
  'aifa': '8ecd7512-2864-440c-93f3-a3cabe62525b',
  'andi': 'fc8d449516de0dfb',
  'utime': 1483228800,
  'dnt': 0,
  'n': 'MyCoolApp',
  'c': 'wifi',
  'cn': 'Comcast',
  'bd': 'Build/13D15',
  'fcm': 'bk3RNwTe3H0CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1'
}

result = requests.get(LAUNCH_URL, params=params)
print result.json()

Tracking Uninstalls in iOS

Singular can track uninstalls on iOS by using Apple's push notifications. If your app doesn't support push notifications yet, see Apple's guide. Once your app supports push notifications, pass the device token returned from APNS when you report the session to Singular.

Notes:

  • We assume you already have a push notification implementation that you are retrieving a device token from.
  • The APNS token is usually binary data in the native form. Pass it to Singular as received from APNS. If your app is altering the token data type for another purpose, make sure to pass it as a hex-encoded string, e.g.: encodedb0adf7c9730763f88e1a048e28c68a9f806ed032fb522debff5bfba010a9b052
Python HTTP cURL
import requests
import json

SDK_KEY = ' sdk keys'
LAUNCH_URL = 'https://s2s.singular.net/api/v1/launch'

params = {
  'a': SDK_KEY,
  'p': 'iOS',
  'i': '162738612',
  'ip': '10.1.2.3',
  've': '9.2',
  'mo': 'iPhone9%2C4',
  'lc': 'en_US',
  'idfa': '8ECD7512-2864-440C-93F3-A3CABE62525B',
  'idfv': '38548D9F-3F73-4D4B-8545-9A920CC89191',
  'utime': 1483228800,
  'dnt': 0,
  'n': 'MyCoolApp',
  'c': 'wifi',
  'cn': 'Comcast',
  'bd': 'Build/13D15',
  'apns_token': 'b0adf7c9730763f88e1a048e28c68a9f806ed032fb522debff5bfba010a9b052'
}

result = requests.get(LAUNCH_URL, params=params)
print result.json()

Complying with Data Privacy Laws

Singular provides privacy-safeguarding functionality to help you cooperate with any partners who may be complying with consumer privacy laws such as GDPR and CCPA. These partners want to be notified if the end-user has consented to share their private information.

If you have implemented a way to ask users for consent to share their information, use the data_sharing_options parameters to notify Singular of the user's choice:

  • Pass "limit_data_sharing":false to indicate that the user consented (opted in) to share their information.
  • Pass "limit_data_sharing":true if the user refused.

Singular will pass this information on to partners who require it to comply with relevant regulations.

Note:

  • The use of the method is optional, but there may be attribution information that the partner will share with Singular only if specifically notified that the user has opted in.
  • Remember to URL-encode the JSON object if you pass it in a GET request.
Field Type Description Usage
limit_data_sharing boolean

Pass this optional value on every launch or evt request to indicate the end-user's preferences.

data_sharing_options=
%7B%22limit_data_sharing%22%3Atrue%7D

Reference: Retrieving the iOS Install Receipt

As you can see in the Session Notification endpoint reference, when reporting a session for an iOS app, you should pass the install receipt in the install_receipt parameter.

To retrieve this value, add the following code to your app:

Objective-C
+ (NSString*)installReceipt {
    // install receipts are iOS 7.0+
    if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_7_0) {
        return nil;
    }
    
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    
    if (receiptURL) {
        NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
        
        if (receipt) {
            return [receipt base64EncodedStringWithOptions:0];
        }
    }
    
    return nil;
}

Reference: Retrieving Device Identifiers and Session Data

This section details how you can retrieve certain values required in the REST API. These values are industry standard, and Apple and Google have documentation on them as well. We have provided a few reference implementations for your convenience.

Retrieving the Google Advertising ID/Limit Ad Tracking (Android Identifiers)

Google Play Services SDK is required to obtain the Advertising ID in your app. Add the following tag as a child of your application element in AndroidManifest.xml:

XML
<meta-data android:name="com.google.android.gms.version"
           android:value="@integer/google_play_services_version" />

If your app build is targeting Android 12/API level 31 or higher, add permissions to access the Google Advertising ID:

XML
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />

Sample code for getting the Google Advertising ID/Limit Ad Tracking parameters:

Java
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;

// Do not call this function from the main thread. Otherwise, 
// an IllegalStateException will be thrown.
public void getIdAndLAT() {
    Info adInfo = null;
    try {
        adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);
    } catch (IOException e) {
        // Unrecoverable error connecting to Google Play services (e.g.,
        // the old version of the service doesn't support getting AdvertisingId).
    } catch (GooglePlayServicesAvailabilityException e) {
        // Encountered a recoverable error connecting to Google Play services. 
    } catch (GooglePlayServicesNotAvailableException e) {
        // Google Play services is not available entirely.
    }

final String GAID = adInfo.getId(); final boolean limitAdTracking = adInfo.isLimitAdTrackingEnabled(); }

Retrieving Locale, Device, and Build for Android

Java
// Locale - lc= query parameter
String locale = Locale.getDefault();

// Model - mo= query parameter
String device = Build.MODEL;

// Build - bd= query parameter
String build = "Build/" + Build.ID;

Retrieving the App Tracking Transparency Authorization Status (iOS)

Starting with iOS 14.5, App Tracking Transparency is required to retrieve the device's IDFA. If you show the App Tracking Transparency prompt, be sure to implement the prompt and handler before attempting to retrieve the IDFA.

Below is an example of how to implement the ATT prompt (optional) and how to retrieve the ATT authorization statue (required):

Objective-C
#import <AppTrackingTransparency/ATTrackingManager.h>

// OPTIONAL if you decide to show the ATT prompt // Show prompt and handle the value. Will only appear once even if called multiple times [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status){ // your authorization handler here }];
// REQUIRED // Reading the current ATT authorization status ATTrackingManagerAuthorizationStatus status = [ATTrackingManager trackingAuthorizationStatus];

Retrieving the IDFA/Limit Ad Tracking (iOS Identifiers)

Starting with iOS 14.5, App Tracking Transparency is required to retrieve the IDFA. If you decide to show the App Tracking Transparency prompt, be sure to implement the prompt and handler before attempting to retrieve the IDFA.

If you do not plan on showing the App Tracking Transparency, the IDFA can still be retrieved (the value will be zeros). The IDFV must be retrieved and sent in any case, as Singular falls back to it if the IDFA is unavailable or all zeros.

The limit-ad-track (isAdvertisingTrackingEnabled) flag is required for iOS 13 and below and used to indicate if a user has opted out of ad tracking. For iOS 14+, the flag is deprecated and is a static value if retrieved. Singular and partners will rely on the newer ATT authorization status value for data handling for privacy flows.

Below is an example of retrieval of the IDFA, IDFV, and the limit-ad-tracking status:

Objective-C Swift
//Import the AdSupport class at the top of your file
@import AdSupport;

Sample code for getting the IDFA/Limit Ad Tracking parameters:

Objective-C Swift
NSString* IDFA = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
NSString* IDFV = [[[UIDevice currentDevice] identifierForVendor] UUIDString];

BOOL isAdvertisingTrackingEnabled = [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled];

Retrieving Locale, Device, and Build for iOS

Objective-C Swift
// Locale - lc= query parameter
NSString *locale = [[NSLocale currentLocale] localeIdentifier];

// Model - mo= query paramter
#import <sys/sysctl.h>
NSString *device() {
    size_t bufferSize = 64;
    NSMutableData * buffer = [[NSMutableData alloc] initWithLength:bufferSize];
    int status = sysctlbyname("hw.machine", buffer.mutableBytes, &bufferSize, NULL, 0);
    if (status != 0) {
        return nil; 
    }
    return [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding];
}

// Build - bd= query parameter
NSString * build () { 
    size_t bufferSize = 64;
    NSMutableData *buffer = [[NSMutableData alloc] initWithLength:bufferSize];
    int status = sysctlbyname("kern.osversion",buffer.mutableBytes, &bufferSize, NULL, 0);
    if (status != 0) {
        return nil;
    }
    return [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding];
}