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.

Reporting Sessions

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 an App session, call the Session Notification Endpoint.

GET https://s2s.singular.net/api/v1/launch

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 Retrieving App 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.

Reporting 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.

GET https://s2s.singular.net/api/v1/evt

Notes:

  • Singular recommends passing events using Singular's standard event and attribute naming convention. Using standard events streamlines mapping and compatibility with your partners standard events in integrations.
  • 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.

Important:

  • 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.

Reporting 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_key from Developer tools > SDK Integration > 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()

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.

Additional Attribution Handling

Supporting Apple Search Ads Campaigns

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_key from Developer tools > SDK Integration > 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.   

Supporting Google Play Install Referrer

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 Integration > 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()
Supporting Meta Install Referrer Attribution

Meta Install Referrer Attribution (Android)

"Meta Referrer" is an Android-specific measurement solution introduced by Facebook to allow advertisers access to granular user-level attribution data for Android app installs (see Facebook's data policies). It is comprised of implementing both "Google Play Install Referrer" (see "Passing Google Install Referrer") and "Meta Install Referrer" technologies for app install measurement. Read more about Meta Referrer in the FAQ on the topic.

To share Meta Install Referrer information with Singnular:

  1. When the app is opened for the first time, retrieve the Meta install referrer according to Meta's documentation.
  2. Report a session to Singular using the Session Notification endpoint including the parameter meta_ref. This parameter is JSON-encoded and has the following attributes:

    Attribute Description
    is_ct The "is_ct" as received from the Meta Install Referrer. (e.g. 0 or 1)
    install_referrer The "install_referrer" as received from the Meta Install Referrer
    actual_timestamp The "actual_timestamp" as received from the Meta Install Referrer (e.g., 1693978124).

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_key from Developer tools > SDK Integration > 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"
  }

Handling Singular Short Links

When the app is opened from a Singular short link, the following parameter should be sent on the launch request to notify the Singular endpoint that the url sent in openuri should be resolved to the Singular long link. 

  • singular_link_resolve_required=true

Singular returns the long link and the App Developer can parse the deep link and passthrough parameters in the link handler. 

Sample Session Notification Call with Short Link resolution

Python
import requests
      import json
  
      SDK_KEY = '[sdk_key from Developer tools > SDK Integration > 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/q5a2',
          'singular_link_resolve_required':'true',
      }
  
      result = requests.get(LAUNCH_URL, params=params)
      print result.json()

Sample Response

{
    "status":"ok",
    "resolved_singular_link":"https://myapp.sng.link/A59c0/nha7?_dl=myapp%3A%2F%2Fdeeplink&_ddl=myapp%3A%2F%2Fdeferred-deeplink&_p=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.

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).

How to send the User ID

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 Integration > 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()

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

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_key from Developer tools > SDK Integration > 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

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_key from Developer tools > SDK Integration > 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 uses limit_data_sharing in "User Privacy Postbacks" as well as passing this information on to partners who require it in order to comply with relevant regulations. See "User Privacy and Limit Data Sharing" for more information.

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

Retrieving App Data

Required iOS Identifiers

  • The IDFV is required on all S2S requests
  • The IDFA should be provided if App Tracking Transparency Consent was provided by the user.
  • The ATT Authorization Status is also required.
How to retrieve iOS Device Data

Retrieving the Identifier for Advertisers (IDFA)

The Identifier for Advertisers (IDFA) helps advertisers track and attribute user actions (e.g., ad clicks, app installs) to specific campaigns, enabling precise ad targeting and campaign optimization.

Starting with iOS 14.5, users must opt-in via the App Tracking Transparency (ATT) framework before apps can access their IDFA. If users do not opt-in, the IDFA is unavailable, limiting tracking capabilities.

Retrieving the Identifier for Vendors (IDFV)

The Identifier for Vendors (IDFV) is a unique identifier assigned by Apple to a device, which is specific to a particular vendor or developer. It remains consistent across all apps from the same vendor on a given device, allowing the vendor to track user behavior and interactions across their app ecosystem without identifying the user personally.

  • Ensure the ATT prompt is shown and handled before attempting to access the IDFA.
  • If you are using ATT, capture the IDFA and pass it back to your server for use on Singular API requests.
  • Capture the IDFV and pass it back to your server for use on Singular API requests.

Example: Requesting ATT Authorization Status to Retrieve IDFA and IDFV with Console Logs

Here is the Objective-C and Swift code snippets to retrieve both the IDFA (Identifier for Advertisers) and IDFV (Identifier for Vendor) with console logs. This code includes handling App Tracking Transparency (ATT) permissions, which are required to access the IDFA starting from iOS 14.5.

Objective-CSwift
#import <AdSupport/AdSupport.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <UIKit/UIKit.h>

- (void)retrieveIdentifiers {
    // Request ATT authorization (iOS 14.5+)


    [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
        dispatch_async(dispatch_get_main_queue(), ^{
            switch (status) {
                case ATTrackingManagerAuthorizationStatusAuthorized: {
                    // ATT authorized, retrieve IDFA


                    NSUUID *idfa = [[ASIdentifierManager sharedManager] advertisingIdentifier];
                    NSLog(@"IDFA: %@", [idfa UUIDString]);
                    break;
                }
                case ATTrackingManagerAuthorizationStatusDenied:
                case ATTrackingManagerAuthorizationStatusRestricted:
                case ATTrackingManagerAuthorizationStatusNotDetermined:
                    // ATT not authorized or not determined


                    NSLog(@"Tracking not authorized or not determined.");
                    break;
                default:
                    NSLog(@"Unknown ATT status.");
                    break;
            }

            // Retrieve IDFV (always available)


            NSUUID *idfv = [[UIDevice currentDevice] identifierForVendor];
            if (idfv != nil) {
                NSLog(@"IDFV: %@", [idfv UUIDString]);
            } else {
                NSLog(@"Unable to retrieve IDFV.");
            }
        });
    }];
}

// Call the method to retrieve identifiers


[self retrieveIdentifiers];
  • IDFA: Requires ATT authorization from iOS 14.5+. Without user consent, the IDFA will return all zeros.
  • IDFV: Always available and should should always be provided on Singular API Requests.

Required Android Identifiers (Google Play Devices)

  • The ASID is required on all S2S requests
  • The AIFA (GAID) should be provided if available.
How to retrieve Android Device Data (Google Play)

Retrieving the Google Advertising Identifier (GAID)

The Google Advertising Identifier (GAID), also known as AIFA in Singular or Android Advertising ID (AAID), is a unique, user-resettable identifier assigned to Android devices. It helps advertisers and app developers track and attribute user actions (e.g., ad clicks, app installs) across apps to specific campaigns, enabling precise ad targeting and campaign optimization, while maintaining user privacy.

JavaKotlin
Dependencies

Make sure you have added the required dependency for Google Play Services in your build.gradle file:

dependencies {
    implementation 'com.google.android.gms:play-services-ads-identifier:17.0.0'
}
Usage

To use this method, simply call it from your activity or application class:

AdIdUtils.getGoogleAdId(getApplicationContext());
Java Code to Retrieve Google Advertising ID (GAID)

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;

import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;

public class AdIdUtils {

    // Method to retrieve the Google Advertising ID (GAID)


    public static void getGoogleAdId(Context context) {
        // Running the task in a background thread


        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    // Retrieve the Advertising ID info


                    Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
                    
                    // Get the GAID (Google Advertising ID)


                    String adId = adInfo.getId();
                    
                    // Check if "Limit Ad Tracking" is enabled by the user


                    boolean isLimitAdTrackingEnabled = adInfo.isLimitAdTrackingEnabled();
                    
                    // Log the results


                    Log.d("GoogleAdID", "Advertising ID: " + adId);
                    Log.d("GoogleAdID", "Limit Ad Tracking Enabled: " + isLimitAdTrackingEnabled);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

Retrieving the App Set ID (ASID)

The Android App Set ID provides a way for developers to track users across their own apps in a privacy-conscious manner. It is particularly useful for analytics and fraud prevention but cannot be used for advertising purposes such as personalized ads or measurement.

JavaKotlin
Dependencies

Make sure you have added the required dependency for Google Play Services in your build.gradle file:

dependencies {
    implementation 'com.google.android.gms:play-services-appset:16.1.0'
}
Usage

To use this function, simply call it from your activity or application class:

AppSetIdUtils.getAppSetId(getApplicationContext());
Java Code to Retrieve App Set ID
import android.content.Context;
import android.util.Log;

import com.google.android.gms.appset.AppSet;
import com.google.android.gms.appset.AppSetIdClient;
import com.google.android.gms.appset.AppSetIdInfo;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;

public class AppSetIdUtils {

    // Method to retrieve the App Set ID


    public static void getAppSetId(Context context) {
        // Get the AppSetIdClient instance


        AppSetIdClient client = AppSet.getClient(context);

        // Retrieve the App Set ID information asynchronously


        Task<AppSetIdInfo> task = client.getAppSetIdInfo();

        task.addOnSuccessListener(new OnSuccessListener<AppSetIdInfo>() {
            @Override
            public void onSuccess(AppSetIdInfo info) {
                // Get the App Set ID and its scope


                String appSetId = info.getId();
                int scope = info.getScope();

                // Log the results


                Log.d("AppSetID", "App Set ID: " + appSetId);
                Log.d("AppSetID", "Scope: " + (scope == AppSetIdInfo.SCOPE_DEVELOPER ? "Developer" : "App"));
            }
        }).addOnFailureListener(e -> {
            // Handle any errors that occur during retrieval


            Log.e("AppSetID", "Failed to retrieve App Set ID", e);
        });
    }
}

Required Android Identifiers (Non-Google Play Devices)

If no ASID or AIFA are available:

  • The AMID (Amazon Identifier) should be provided. Amazon Devices Only.
How to retrieve the Amazon Advertising ID (Non-Google Play)

Retrieving the Amazon ID (AMID)

To capture the Amazon Advertising Identifier in your Android app, you can use the Settings.Secure class to retrieve the identifier and check the user's ad tracking preferences. Here's a clean and simple code example based on the information provided by Amazon's documentation:

Make sure to handle scenarios where the Advertising ID might not be available (e.g., on non-Fire OS devices or older versions of Fire OS).

Always respect the user's Limit Ad Tracking preference when using this identifier for advertising or analytics purposes. This code should work on Amazon Fire devices running Fire OS 5.1 or later, as per Amazon's guidelines

JavaKotlin
Usage

You can call this method from your activity or service by passing in the ContentResolver:

// Example usage in an Activity


AdvertisingIdHelper.getAmazonAdvertisingId(getContentResolver());
Java Code to Retrieve the Amazon Advertising ID (AMID)
import android.content.ContentResolver;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;

public class AdvertisingIdHelper {

    public static void getAmazonAdvertisingId(ContentResolver contentResolver) {
        String advertisingID = "";
        boolean limitAdTracking = false;

        try {
            // Get user's ad tracking preference


            limitAdTracking = (Settings.Secure.getInt(contentResolver, "limit_ad_tracking") == 0) ? false : true;

            // Get the Amazon Advertising ID


            advertisingID = Settings.Secure.getString(contentResolver, "advertising_id");

            // Log the values for demonstration purposes


            Log.d("AdvertisingID", "Amazon Advertising ID: " + advertisingID);
            Log.d("LimitAdTracking", "Limit Ad Tracking: " + limitAdTracking);

        } catch (SettingNotFoundException e) {
            // Handle case where settings are not available (e.g., non-Fire OS devices)


            Log.e("AdvertisingID", "Advertising ID not supported on this device", e);
        }
    }
}
  • The OAID (Open Advertising Identifier) should be provided. China domestic devices.
How to retrieve the Open Advertising ID (Non-Google Play)

Retrieving the Open Advertising ID (OAID)

The Open Advertising Identifier (OAID) is a unique, anonymous identifier used for advertising purposes on Android devices, particularly those manufactured in China. It was introduced by the Mobile Security Alliance (MSA) as an alternative to Google's Advertising ID (GAID) for devices where Google Play Services are unavailable or not supported, such as in the Chinese market.

The OAID is primarily used for advertising attribution and user tracking in environments where Google Play Services are restricted, allowing advertisers and developers to track user behavior while maintaining anonymity.

OAID is available on most Chinese-manufactured Android devices, including those from brands like Huawei, Xiaomi, and others. It can be accessed using the MSA SDK or Huawei Mobile Services (HMS).

JavaKotlin
Dependencies

Ensure your build.gradle file includes the necessary dependencies for the MSA SDK.

dependencies {
    implementation 'com.bun.msa.sdk:msa:1.0.26'  // Example version; check for the latest one


}
Java Code to Retrieve OAID
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.bun.msa.sdk.DeviceId;
import com.bun.msa.sdk.DeviceIdSupplier;
import com.bun.msa.sdk.IIdentifierListener;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "OAIDExample";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize and request OAID


        getOAID();
    }

    private void getOAID() {
        try {
            // Create a DeviceId instance and request OAID asynchronously


            DeviceId deviceId = new DeviceId(this);
            deviceId.getDeviceIds(new IIdentifierListener() {
                @Override
                public void onSupport(boolean isSupport, DeviceIdSupplier supplier) {
                    if (isSupport && supplier != null) {
                        // Retrieve OAID from supplier


                        String oaid = supplier.getOAID();
                        Log.d(TAG, "OAID: " + oaid);
                    } else {
                        Log.e(TAG, "OAID not supported on this device");
                    }
                }
            });
        } catch (Exception e) {
            Log.e(TAG, "Error retrieving OAID", e);
        }
    }
}
  • If no other device identifier exists, then you may provide the ANDI (Android ID).
How to retrieve the Android ID (Non-Google Play)

Retrieving the Android ID (ANDI)

The Android ID is a unique 64-bit identifier generated by the Android operating system when a device is first set up. It is designed to be persistent across the lifetime of the device, but it can be reset under certain conditions such as a factory reset.

The Android ID is unique to each device and, starting from Android 8.0 (Oreo), it is scoped per app and per user. This means that different apps on the same device will receive different Android IDs unless they share the same signing key.

The Android ID remains constant unless the device undergoes a factory reset or if an app is uninstalled and reinstalled after an OTA (over-the-air) update.

JavaKotlin
Usage

To retrieve the Android ID in an Android app, you can use the following code snippet:

import android.provider.Settings;
import android.content.Context;

String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

Required Web Identifiers

  • The SDID is required on all S2S requests
How to retrieve Singular Web SDK Device ID (SDID)

Retrieving the Singular Web SDK Device ID (SDID)

Description

Dependencies

You must have the Singular Web SDK implemented.

Usage

To use this method, simply call it from your web site code after the Singular SDK has Initialized:

window.singularSdk.getSingularDeviceId()

Required Mobile Device Params

  • The Locale, Make, Model, and Build are required on all S2S requests
How to retrieve Locale, Device Model, and Build

Retrieving Locale, Device Model, and Build for Android

Objective-CSwiftJavaKotlin

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <sys/sysctl.h>

// Retrieve the Locale


NSString *retrieveLocale() {
    NSString *locale = [[NSLocale currentLocale] localeIdentifier];
    NSLog(@"Locale: %@", locale);
    return locale;
}

// Retrieve the Device Model


NSString *deviceModel() {
    size_t bufferSize = 64;
    char model[bufferSize];
    int status = sysctlbyname("hw.machine", model, &bufferSize, NULL, 0);
    
    if (status == 0) {
        NSString *deviceModel = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];
        NSLog(@"Device Model: %@", deviceModel);
        return deviceModel;
    } else {
        NSLog(@"Unable to retrieve device model.");
        return nil;
    }
}

// Retrieve the Build Version


NSString *buildVersion() {
    size_t bufferSize = 64;
    char build[bufferSize];
    int status = sysctlbyname("kern.osversion", build, &bufferSize, NULL, 0);
    
    if (status == 0) {
        NSString *buildVersion = [NSString stringWithCString:build encoding:NSUTF8StringEncoding];
        NSLog(@"Build Version: %@", buildVersion);
        return buildVersion;
    } else {
        NSLog(@"Unable to retrieve build version.");
        return nil;
    }
}

// Example usage


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // Retrieve Locale


        NSString *locale = retrieveLocale();
        
        // Retrieve Device Model


        NSString *model = deviceModel();
        
        // Retrieve Build Version


        NSString *build = buildVersion();
        
        // Log results


        if (locale) {
            NSLog(@"Locale: %@", locale);
        }
        
        if (model) {
            NSLog(@"Device Model: %@", model);
        }
        
        if (build) {
            NSLog(@"Build Version: %@", build);
        }
    }
    return 0;
}

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.

How to retrieve iOS Install Receipt

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

Objective-CSwift
// ReceiptManager.h
@interface ReceiptManager : NSObject
+ (nullable NSString *)getInstallReceipt;
@end

// ReceiptManager.m
#import <StoreKit/StoreKit.h>

@implementation ReceiptManager

+ (nullable NSString *)getInstallReceipt {
    if (@available(iOS 18.0, *)) {
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        __block NSString *result = nil;
        
        [SKPaymentQueue.defaultQueue addTransactionObserver:[[SKPaymentTransactionObserver alloc] init]];
        
        if (@available(iOS 18.0, *)) {
            [AppTransaction.shared fetchWithCompletionHandler:^(AppTransaction *transaction, NSError *error) {
                if (error) {
                    NSLog(@"Failed to get app transaction: %@", error.localizedDescription);
                } else {
                    result = transaction.jwsRepresentation;
                }
                dispatch_semaphore_signal(semaphore);
            }];
        }
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        return result;
        
    } else {
        NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
        if (!receiptURL) {
            NSLog(@"Receipt URL not found");
            return nil;
        }
        
        NSError *error = nil;
        NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL 
                                                   options:NSDataReadingUncached 
                                                     error:&error];
        
        if (error) {
            NSLog(@"Failed to read receipt: %@", error.localizedDescription);
            return nil;
        }
        
        return [receiptData base64EncodedStringWithOptions:0];
    }
}

@end