From 13f7affb25fcd61eb785210a5a09d7617bfb4f21 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 7 Apr 2026 10:10:00 +0000 Subject: [PATCH 1/2] docs: add SDK setup guide to Adjust integration page Add client-side code examples for passing the Adjust device ID and IDFA to Superwall across all platforms (iOS, Android, Flutter, Expo/RN). The existing page only covered dashboard configuration but was missing the actual SDK code developers need to write. Also updates the iOS setIntegrationAttributes reference to list all common IntegrationAttribute types including .adjustId. Co-Authored-By: Claude Opus 4.6 --- content/docs/integrations/adjust.mdx | 147 ++++++++++++++++++ .../setIntegrationAttributes.mdx | 7 + 2 files changed, 154 insertions(+) diff --git a/content/docs/integrations/adjust.mdx b/content/docs/integrations/adjust.mdx index 96d1377f..ec77b679 100644 --- a/content/docs/integrations/adjust.mdx +++ b/content/docs/integrations/adjust.mdx @@ -51,6 +51,153 @@ Fill out the following fields and **click** the **Enable Adjust** button at the } ``` +### SDK setup + +After enabling Adjust in the dashboard, you need to pass the Adjust device ID from your app so Superwall can attribute subscription events. Without the `adjustId`, events are silently skipped. + +#### Prerequisites + +- Superwall SDK installed and configured +- Adjust SDK installed ([iOS](https://github.com/adjust/ios_sdk), [Android](https://github.com/adjust/android_sdk)) +- For iOS: `AppTrackingTransparency` and `AdSupport` frameworks linked + +#### iOS (Swift) + +Add the `NSUserTrackingUsageDescription` key to your `Info.plist` to enable IDFA access: + +```xml +NSUserTrackingUsageDescription +We use this identifier to measure ad performance and attribute subscriptions. +``` + +Then pass the Adjust device ID and IDFA to Superwall after both SDKs have initialized: + +```swift +import SuperwallKit +import AdjustSdk +import AppTrackingTransparency +import AdSupport + +func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? +) -> Bool { + // 1. Configure Superwall + Superwall.configure(apiKey: "YOUR_SUPERWALL_API_KEY") + + // 2. Configure Adjust + let adjustConfig = ADJConfig( + appToken: "YOUR_ADJUST_APP_TOKEN", + environment: ADJEnvironmentProduction + ) + Adjust.initSdk(adjustConfig) + + // 3. Request ATT permission, then pass identifiers + ATTrackingManager.requestTrackingAuthorization { _ in + self.syncAdjustIdentifiers() + } + + return true +} + +private func syncAdjustIdentifiers() { + Adjust.adid { adid in + guard let adid else { return } + + // Required — events are skipped without this + Superwall.shared.setIntegrationAttribute(.adjustId, adid) + + // Optional — enriches attribution data on iOS + if ATTrackingManager.trackingAuthorizationStatus == .authorized { + let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString + Superwall.shared.setUserAttributes(["idfa": idfa]) + } + } +} +``` + + + The `adjustId` is the **only required** identifier. If the user denies the ATT prompt, the IDFA will be unavailable but events will still be attributed via the Adjust device ID. + + +#### Android (Kotlin) + +Pass the Adjust device ID and GPS advertising ID to Superwall after initialization: + +```kotlin +import com.superwall.sdk.Superwall +import com.superwall.sdk.analytics.IntegrationAttribute +import com.adjust.sdk.Adjust +import com.google.android.gms.ads.identifier.AdvertisingIdClient + +// After Superwall.configure() and Adjust.initSdk() + +Adjust.getAdid { adid -> + if (adid != null) { + // Required — events are skipped without this + Superwall.instance.setIntegrationAttributes( + mapOf(IntegrationAttribute.ADJUST_ID to adid) + ) + } +} + +// Optional — enriches attribution on Android +// Must be called off the main thread +lifecycleScope.launch(Dispatchers.IO) { + try { + val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(applicationContext) + if (!adInfo.isLimitAdTrackingEnabled) { + Superwall.instance.setUserAttributes( + mapOf("gps_adid" to adInfo.id) + ) + } + } catch (e: Exception) { + // Advertising ID not available + } +} +``` + +#### Flutter (Dart) + +```dart +import 'package:superwallkit_flutter/superwallkit_flutter.dart'; +import 'package:adjust_sdk/adjust.dart'; + +// After Superwall.configure() and Adjust.initSdk() + +final adid = await Adjust.getAdid(); +if (adid != null) { + await Superwall.shared.setIntegrationAttribute( + IntegrationAttribute.adjustId, + adid, + ); +} +``` + +#### Expo / React Native + +```tsx +import Superwall from "@superwall/react-native-superwall"; +import { Adjust } from "react-native-adjust"; + +// After Superwall.configure() + +const adid = await Adjust.getAdid(); +if (adid) { + await Superwall.shared.setIntegrationAttributes({ + adjustId: adid, + }); +} +``` + +#### Identifier reference + +| Identifier | How to set | Required | +|------------|-----------|----------| +| `adjustId` | `setIntegrationAttribute(.adjustId, adid)` | **Yes** — events are skipped without it | +| `idfa` (iOS) | `setUserAttributes(["idfa": idfa])` | No — enriches iOS attribution | +| `gps_adid` (Android) | `setUserAttributes(["gps_adid": gpsAdId])` | No — enriches Android attribution | + ### Event mapping Superwall events are transformed into Adjust event names using the standard mapper: diff --git a/content/docs/ios/sdk-reference/setIntegrationAttributes.mdx b/content/docs/ios/sdk-reference/setIntegrationAttributes.mdx index 91e88405..9bd9a226 100644 --- a/content/docs/ios/sdk-reference/setIntegrationAttributes.mdx +++ b/content/docs/ios/sdk-reference/setIntegrationAttributes.mdx @@ -59,9 +59,16 @@ print("Current attributes: \(attributes)") ## IntegrationAttribute Types Common integration attributes include: +- `.adjustId` - Adjust device ID (required for Adjust integration) +- `.amplitudeDeviceId` - Amplitude device ID - `.amplitudeUserId` - Amplitude user ID +- `.appsflyerId` - AppsFlyer user ID +- `.brazeAliasName` - Braze alias name +- `.brazeAliasLabel` - Braze alias label - `.mixpanelDistinctId` - Mixpanel distinct ID +- `.firebaseAppInstanceId` - Firebase app instance ID - `.firebaseInstallationId` - Firebase installation ID (4.10.8+) +- `.clevertapId` - CleverTap user ID - `.appstackId` - Appstack identifier (4.12.11+) - `.custom(String)` - Custom attribute key From 01ec1551581b8f6621401f3b34171549dd1f9709 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 7 Apr 2026 10:49:20 +0000 Subject: [PATCH 2/2] fix: correct iOS optional handling and Expo/RN code example for Adjust - ADJConfig init returns optional, use force-unwrap for initSdk - Use useUser() hook from expo-superwall instead of Superwall.shared - Use Adjust callback-based getAdid() instead of async/await Co-Authored-By: Claude Opus 4.6 --- content/docs/integrations/adjust.mdx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/content/docs/integrations/adjust.mdx b/content/docs/integrations/adjust.mdx index ec77b679..a827126d 100644 --- a/content/docs/integrations/adjust.mdx +++ b/content/docs/integrations/adjust.mdx @@ -90,7 +90,7 @@ func application( appToken: "YOUR_ADJUST_APP_TOKEN", environment: ADJEnvironmentProduction ) - Adjust.initSdk(adjustConfig) + Adjust.initSdk(adjustConfig!) // 3. Request ATT permission, then pass identifiers ATTrackingManager.requestTrackingAuthorization { _ in @@ -177,17 +177,18 @@ if (adid != null) { #### Expo / React Native ```tsx -import Superwall from "@superwall/react-native-superwall"; +import { useUser } from "expo-superwall"; import { Adjust } from "react-native-adjust"; -// After Superwall.configure() +// Inside your component, after Superwall is configured +const { setIntegrationAttributes } = useUser(); -const adid = await Adjust.getAdid(); -if (adid) { - await Superwall.shared.setIntegrationAttributes({ - adjustId: adid, - }); -} +// After Adjust has initialized +Adjust.getAdid((adid) => { + if (adid) { + setIntegrationAttributes({ adjustId: adid }); + } +}); ``` #### Identifier reference