---
id: "integrations/attribution/singular"
title: "Singular"
description: "With our Singular integration you can:"
permalink: "/docs/integrations/attribution/singular"
slug: "singular"
version: "current"
original_source: "docs/integrations/attribution/singular.mdx"
---

> **AI agents:** This is the Markdown version of a RevenueCat documentation page. For the complete documentation index, see [llms.txt](https://www.revenuecat.com/docs/llms.txt).

With our Singular integration you can:

- Accurately track subscriptions generated from Singular campaigns, allowing you to know precisely how much revenue your campaigns generate.
- Send trial conversions and renewals directly from RevenueCat to Singular, allowing for tracking without an app open.
- Continue to follow your cohorts for months to know the long tail revenue generated by your campaigns.

### Integration at a glance

| Revenue support | Supports Negative Revenue |   Sends Sandbox Events   | Includes Customer Attributes | Sends Transfer Events |      Optional Event Types       |
| :-------------: | :-----------------------: | :----------------------: | :--------------------------: | :-------------------: | :-----------------------------: |
|       ✅        |            ✅             | Requires sandbox SDK key |        Matching only         |          ❌           | [See Event types](#event-types) |

For a cross-provider view of identifiers, revenue support, sandbox behavior, and attribution responsibilities, see the [attribution provider comparison](https://www.revenuecat.com/docs/integrations/attribution/provider-comparison).

## Before you begin

Review [Getting Started with Attribution Integrations](https://www.revenuecat.com/docs/integrations/attribution/getting-started) for how attribution integrations fit together, then use the [setup checklist](https://www.revenuecat.com/docs/integrations/attribution/setup-checklist) as a reference for required lifecycle events, reporting choices, duplicate-event risks, and testing checks.

The following considerations are specific to Singular:

- Singular has two server-to-server Event API versions. **Event Endpoint V2** is required for Singular accounts created on or after **July 15, 2026**. **Event Endpoint V1** remains available only to eligible legacy Singular accounts created before that date. Choose the version in RevenueCat that matches your Singular account.
- Event Endpoint V2 requires the Singular Device ID (SDID) from the Singular SDK. RevenueCat cannot derive SDID with `collectDeviceIdentifiers()`. Your app must pass SDID to RevenueCat with `setSingularDeviceID()`.
- If your app shows a paywall very early, a customer can purchase before SDID syncs to RevenueCat. Keep the Singular SDID callback in your implementation so `setSingularDeviceID()` runs when SDID becomes available.
- Keep the Singular SDK installed and initialized when you use Event Endpoint V2, or when you rely on Singular for install and session tracking in a hybrid integration.
- Turn off Singular SDK purchase or revenue tracking for the same subscription events RevenueCat sends, unless you intentionally manage deduplication in Singular.
- The Singular integration supports mobile App Store and Play Store events only. Stripe and other web billing events aren't sent to Singular.
- In Singular's Apps settings, do not enable **Reject IAP without Receipt**. RevenueCat validates purchases before sending events and doesn't include store receipts in the Singular payload.
- RevenueCat sends Singular events server-to-server and can't modify SKAdNetwork conversion values from those events.

## 1. Install the Singular SDK

Before RevenueCat can deliver events with Event Endpoint V2, your app must run the Singular SDK so it can generate SDID. Refer to the [Singular developer documentation](https://support.singular.net/hc/en-us/articles/360037640172-Integrating-a-Singular-SDK-Planning-and-Prerequisites) for the latest installation instructions.

If you use Event Endpoint V1 with platform device identifiers only, the Singular SDK is still recommended when Singular also tracks installs or sessions in your app.

## 2. Send attribution data to RevenueCat

Singular matches RevenueCat events using either SDID (Event Endpoint V2) or platform device identifiers (Event Endpoint V1). Configure the path that matches the Event API version you select in RevenueCat.

### Event Endpoint V2 (recommended)

Use Event Endpoint V2 if your Singular account was created on or after July 15, 2026, or if Singular requires SDID for your account.

| Key                 | Description                                                                  | Required |
| :------------------ | :--------------------------------------------------------------------------- | :------- |
| `$singularDeviceId` | Singular Device ID (SDID) generated by the Singular SDK for this app install | ✅       |

Pass SDID to RevenueCat with `setSingularDeviceID()`. SDID isn't collected by `collectDeviceIdentifiers()` and can't be entered manually in the RevenueCat dashboard, because it's per device and per install. Set SDID after the RevenueCat SDK is configured and before the first purchase occurs whenever possible.

Consent changes such as App Tracking Transparency affect platform identifiers used by Event Endpoint V1, not the SDID required for Event Endpoint V2. If you use the legacy API, follow the [Event Endpoint V1 (legacy)](#event-endpoint-v1-legacy) guidance for `collectDeviceIdentifiers()` and ATT.

The examples below show the recommended app-side flow:

1. Configure the RevenueCat SDK.
2. Initialize the Singular SDK.
3. Pass SDID to RevenueCat with `setSingularDeviceID()` in the Singular SDK's SDID callback when it becomes available.
4. Keep the SDID callback in place so `setSingularDeviceID()` runs again when Singular provides or updates SDID, such as after SDK initialization or reinstall.

Use RevenueCat SDK **5.87.0+** on iOS or **10.19.0+** on Android when setting `$singularDeviceId` from your app.

#### iOS

- Register `sdidReceivedHandler` on your `SingularConfig` object. Singular
  calls it when SDID is available, including SDIDs restored from a previous
  install.
- See Singular's [iOS SDK configuration
  reference](https://support.singular.net/hc/en-us/articles/42098616285339-iOS-SDK-Configuration-Methods-Reference).

#### Android

- Register an `SDIDAccessorHandler` with `withSdidAccessorHandler()` and
  forward both `sdidReceived` and `didSetSdid` to RevenueCat.
- See Singular's [Android SDK basic
  integration](https://support.singular.net/hc/en-us/articles/360037581952-Android-SDK-Basic-Integration).

**Swift**

```swift
import RevenueCat
import Singular // Provides SingularConfig

// ...
Purchases.configure(withAPIKey: "public_sdk_key")
// ...

guard let config = SingularConfig(apiKey: "YOUR_SDK_KEY", andSecret: "YOUR_SDK_SECRET") else {
    fatalError("Failed to create Singular config")
}

// Pass the SDID to RevenueCat when the Singular SDK makes it available.
config.sdidReceivedHandler = { sdid in
    Purchases.shared.attribution.setSingularDeviceID(sdid)
}

Singular.start(config)
```

**Kotlin**

```kotlin
import com.revenuecat.purchases.Purchases
import com.singular.sdk.SDIDAccessorHandler
import com.singular.sdk.Singular
import com.singular.sdk.SingularConfig

// ...
Purchases.configure(this, "public_sdk_key")
// ...

val config = SingularConfig("YOUR_SDK_KEY", "YOUR_SDK_SECRET")
    .withSdidAccessorHandler(object : SDIDAccessorHandler {
        override fun sdidReceived(result: String) {
            Purchases.sharedInstance.setSingularDeviceID(result)
        }

        override fun didSetSdid(result: String) {
            Purchases.sharedInstance.setSingularDeviceID(result)
        }
    })

Singular.init(applicationContext, config)
```

### Event Endpoint V1 (legacy)

Use Event Endpoint V1 only if your Singular account is eligible for Singular's legacy Event API and doesn't require SDID.

RevenueCat sends Singular events only when the required [Customer Attributes](https://www.revenuecat.com/docs/customers/customer-attributes) below are set for the purchase platform.

| Key          | Description                                                                                                                                     | Required                                        |
| :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------- |
| `$idfa`      | iOS [advertising identifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/advertisingidentifier) UUID                | ✅ (iOS)                                        |
| `$idfv`      | iOS [vendor identifier](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor) UUID                                      | ✅ (iOS)                                        |
| `$gpsAdId`   | Google [advertising identifier](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info) | ✅ (Android, one of `$gpsAdId` or `$androidId`) |
| `$androidId` | Android [device identifier](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID)                                | ✅ (Android, one of `$gpsAdId` or `$androidId`) |
| `$ip`        | The IP address of the device                                                                                                                    | ⚠️ (optional)                                   |

These properties can be set manually, like any other [Customer Attributes](https://www.revenuecat.com/docs/customers/customer-attributes), or through `collectDeviceIdentifiers()`. Set them after the RevenueCat SDK is configured and before the first purchase occurs whenever possible.

The examples below show the recommended app-side flow:

1. Configure the RevenueCat SDK.
2. Call `collectDeviceIdentifiers()`.
3. Collect device identifiers again if a new value becomes available, such as after ATT permission is granted.

#### iOS

- If you request App Tracking Transparency permission to access the IDFA,
  call `collectDeviceIdentifiers()` again after the customer accepts
  permission to update the `$idfa` attribute in RevenueCat.
- The AdSupport framework is required to access the IDFA parameter. In
  Xcode, add `AdSupport.framework` to your app target under **Frameworks,
  Libraries, and Embedded Content**, leave it set to **Do Not Embed**, then
  import `AdSupport` in your Swift file.

#### Android

- RevenueCat's current Android SDKs don't collect Android ID. Google's
  Advertising ID (`$gpsAdId`) acts as the primary Android device identifier
  in RevenueCat and when connecting with third-party integrations.

**Swift**

```swift
import RevenueCat
import AdSupport // Required for IDFA collection

// ...
Purchases.configure(withAPIKey: "public_sdk_key")
// ...

Purchases.shared.attribution.collectDeviceIdentifiers()
```

**Kotlin**

```kotlin
import com.revenuecat.purchases.Purchases

// ...
Purchases.configure(this, "public_sdk_key")
// ...

Purchases.sharedInstance.collectDeviceIdentifiers()
```

For endpoint URLs, transport differences, and field-level mapping between V1 and V2, see the [Singular event delivery reference](https://www.revenuecat.com/docs/integrations/attribution/reference/singular).

### (Optional) Send campaign data to RevenueCat

RevenueCat isn't an attribution network and can't determine which ad drove an install or conversion. If Singular or another source gives your app final campaign values, you can attach them to the customer using reserved [Customer Attributes](https://www.revenuecat.com/docs/customers/customer-attributes).

:::warning[Set final campaign values only]
Don't set temporary placeholders like `Organic`, `Unknown`, or `No User Consent` while waiting for final attribution. Reserved attribution attributes can only be set once per customer. If Singular later returns final campaign values, RevenueCat can't replace a placeholder you already set.
:::

| Key            | Description                                 |
| :------------- | :------------------------------------------ |
| `$mediaSource` | The attribution source or network           |
| `$campaign`    | The campaign name or identifier             |
| `$adGroup`     | The ad group name or identifier             |
| `$ad`          | The ad name or identifier                   |
| `$keyword`     | The keyword associated with the attribution |
| `$creative`    | The creative name or identifier             |

## 3. Configure Singular in RevenueCat

After your app sends the required identifiers or SDID to RevenueCat, enable the integration in the RevenueCat dashboard.

1. Go to your dashboard, and select your project.
2. In the lower-left corner, select **Integrations**.
3. Under **Attribution**, select **Singular**.
4. Add your production SDK key from **Settings → SDK** in Singular.
5. Add a sandbox SDK key. To prevent RevenueCat from sending sandbox events to your production environment in Singular, use a different SDK key from production.
6. Select the **Event API version** that matches your Singular account:
   - **v2** for Singular accounts created on or after July 15, 2026, and for any account that requires SDID.
   - **v1** only for eligible legacy Singular accounts that still accept platform device identifiers without SDID.
7. (Optional) Enable **Report early renewals** if you want RevenueCat to send a renewal's occurrence time when a store processes it early, instead of the time when the new subscription period is due to start.
8. Configure event names for each lifecycle event RevenueCat should send, or choose the default event names.
9. Select whether you want sales reported as gross revenue (before app store commission), or after store commission and/or estimated taxes. Use the same reporting mode when comparing Singular-side revenue to RevenueCat revenue metrics. Learn more about [taxes and commissions](https://www.revenuecat.com/docs/dashboard-and-metrics/taxes-and-commissions).

### Event types

RevenueCat sends the core subscription lifecycle events described in the [setup checklist](https://www.revenuecat.com/docs/integrations/attribution/setup-checklist#configure-provider-communication).

Singular also supports these optional events:

| Optional event            | Sent when                                               |
| :------------------------ | :------------------------------------------------------ |
| Non-subscription purchase | A user makes a one-time (non-subscription) purchase     |
| Uncancellation            | A user re-enables auto-renew after cancelling           |
| Subscription paused       | A subscription enters a paused state                    |
| Expiration                | A subscription expires and access is lost               |
| Billing issue             | RevenueCat detects a billing issue for the subscription |
| Product change            | A user changes the product of their subscription        |

For V1 and V2 request shapes, identifier requirements, and RevenueCat field mapping, see the [Singular event delivery reference](https://www.revenuecat.com/docs/integrations/attribution/reference/singular).

## 4. Test the Singular integration

Before rolling out the integration, test with a new customer after the SDK, customer attributes, and dashboard settings are configured.

1. Make a sandbox purchase with a new customer.

2. In the RevenueCat [Customer Profile](https://www.revenuecat.com/docs/dashboard-and-metrics/customer-profile#customer-details), confirm the required attributes from [Send attribution data to RevenueCat](#2-send-attribution-data-to-revenuecat) are present. For Event Endpoint V2, confirm `$singularDeviceId` is set. For Event Endpoint V1, confirm the platform identifiers for the purchase store are set.

3. In [Customer History](https://www.revenuecat.com/docs/dashboard-and-metrics/customer-profile#customer-history), open the sandbox purchase event and confirm the Singular delivery row exists. To compare the request with readable examples for your selected Event API version, see the [Singular event delivery reference](https://www.revenuecat.com/docs/integrations/attribution/reference/singular). If RevenueCat doesn't show a Singular delivery row, see [no provider delivery row troubleshooting](https://www.revenuecat.com/docs/integrations/attribution/troubleshooting#no-provider-delivery-row-appears-in-revenuecat).

4. In Singular, verify the event in **Export logs**. Revenue from RevenueCat-delivered events may not appear in Singular's SDK console even when Singular processed the event as a revenue event in Export logs.

:::success[You've done it!]
You should start seeing events from RevenueCat appear in Singular.
:::
