Singular

Singular is a Mobile Measurement Partner (MMP) platform that collects and presents data from marketing campaigns.

Adapty sends the subscription events you select to Singular. In the Singular dashboard, you can then see how much revenue each campaign generates and evaluate the effectiveness of your advertising.

Set up integration

Connect Adapty to Singular

To set up the integration with Singular, go to Integrations > Singular in your Adapty Dashboard, turn on a toggle, and fill out the fields.

singular-creds.webp

The following credentials are available:

  • Singular SDK Key: Required. The production SDK key for your Singular app.
  • Singular SDK Key (Sandbox): Optional. The SDK key for your sandbox Singular app. If not set, sandbox events will not be sent to Singular.

Both keys can be found in the Singular dashboard under Developer tools -> SDK Keys -> SDK Key (not SDK Secret):

4bc50d1-singular_sdk_key.webp

Configure events and tags

Below the credentials, there are three groups of events you can send to Singular from Adapty. For the full list of Adapty events, see Events.

e67de0c-singular_events.webp

We recommend using the default event names provided by Adapty. But you can change the event names based on your needs.

Adapty sends subscription events to Singular server-to-server, so you can view all subscription events in your Singular dashboard and link them to your acquisition campaigns.

Warning

Profiles created before you set up the integration can’t deliver their events to Singular.

Connect your app to Singular

Singular enables the Singular Device ID (SDID) by default for accounts created on or after July 15, 2026. These accounts accept events only through the v2 Event API, and Adapty sends an event to v2 only when the user’s profile has an SDID. To deliver events to such an account, pass the SDID to Adapty from your app.

If your Singular account was created before July 15, 2026, and SDID isn’t enabled on it, skip this step. Adapty sends your events to the v1 Event API, and no app code is needed.

  1. Activate Adapty, then start the Singular SDK with an SDID callback: sdidReceivedHandler on iOS, SDIDAccessorHandler on Android, sdidReceivedCallback on React Native and Flutter, and SingularSdidAccessorHandler on Unity.
  2. Wait for Singular to call the callback. The SDID reaches your app asynchronously, after the Singular SDK starts. Singular calls the callback on every launch, including when the SDID is already stored on the device.
  3. Inside the callback, pass the SDID to Adapty with setIntegrationIdentifier() and the singular_sdid key. No Adapty SDK has a predefined constant for this key, so write the key as a string literal.
  4. Call Adapty.identify() only after setIntegrationIdentifier() completes. Adapty creates an anonymous profile at activation, then switches to the identified profile once identify() resolves. An SDID set during that switch can be lost.

Event structure

Adapty picks the Singular Event API version for each event by whether the user’s profile has an SDID:

  • With an SDID: Adapty sends a POST request to https://s2s.singular.net/api/v2/evt with a form-urlencoded body. The sdid parameter replaces the device identifiers idfa, idfv, aifa, andi, and asid. Booleans are sent as true or false.
  • Without an SDID: Adapty sends a GET request to https://s2s.singular.net/api/v1/evt with query parameters.

Both versions carry the same parameters otherwise. A v1 event is structured like this:

{
  "n": "subscription_renewed",
  "a": "singular_sdk_key_123",
  "p": "iOS",
  "i": "com.example.app",
  "ip": "192.168.100.1",
  "idfa": "00000000-0000-0000-0000-000000000000",
  "idfv": "00000000-0000-0000-0000-000000000000",
  "ve": "17.0.1",
  "att_authorization_status": 3,
  "custom_user_id": "user_12345",
  "utime": 1709294400,
  "partner": "adapty",
  "use_ip": false,
  "is_revenue_event": true,
  "amt": 9.99,
  "cur": "USD",
  "purchase_product_id": "yearly.premium.6999",
  "purchase_transaction_id": "GPA.3383...",
  "e": "{\"is_revenue_event\":true,\"amt\":9.99,\"cur\":\"USD\",\"purchase_product_id\":\"yearly.premium.6999\",\"purchase_transaction_id\":\"GPA.3383...\"}"
}

Where:

ParameterTypeDescription
nStringThe event name (mapped from Adapty event).
aStringYour Singular SDK Key.
pStringPlatform (“iOS” or “Android”).
iStringStore App ID (Bundle ID).
ipStringUser’s IP address.
sdidStringv2 only. Singular Device ID, from the singular_sdid integration identifier.
idfaStringiOS, v1 only. ID for Advertisers (uppercase).
idfvStringiOS, v1 only. ID for Vendors (uppercase).
aifaStringAndroid, v1 only. Google Advertising ID (lowercase).
andiStringAndroid, v1 only. Android ID (lowercase).
asidStringAndroid, v1 only. App Set ID (lowercase).
veStringOS version.
att_authorization_statusIntegeriOS only. ATT status (e.g., 3 for authorized).
custom_user_idStringThe user’s Customer User ID.
utimeLongUNIX timestamp of the event in seconds.
partnerStringAlways adapty. Identifies the event as sent by Adapty.
use_ipBooleantrue when Adapty has no IP address for the user.
is_revenue_eventBooleantrue if the event contains revenue. Sent only with revenue events.
amtFloatRevenue amount.
curStringCurrency code (e.g., “USD”).
purchase_product_idStringThe Product ID from the store.
purchase_transaction_idStringOriginal transaction ID.
eStringJSON string containing event details (see below).

The e parameter (custom event data) is a JSON-encoded string containing:

ParameterTypeDescription
is_revenue_eventBooleantrue if the event contains revenue.
amtFloatRevenue amount.
curStringCurrency code.
purchase_product_idStringThe Product ID from the store.
purchase_transaction_idStringOriginal transaction ID.

Troubleshooting

Events fail with invalid api version: v1

Your Singular account was created on or after July 15, 2026, and accepts events only through the v2 Event API. Adapty sent the event to v1 because the user’s profile has no SDID. To fix this, pass the SDID to Adapty from your app, as described in Connect your app to Singular. Events from users on an app version without the setIntegrationIdentifier() call keep failing until those users update the app.

access_level_updated shows as failed in the Event Feed

access_level_updated is a webhook-only event. Adapty never sends it to this integration. But Adapty records an outcome for every enabled integration, and an unsupported event is displayed as a failure.