| title | Integration |
|---|---|
| category | 5f9705393c689a065c409b23 |
| parentDoc | 6370c9e2441a4504d6bca3bd |
| order | 1 |
| hidden | false |
To initialize the plugin, create a game object and add an init script to it.
- Manual integration
- Session Ready Listener
- Collect IDFA with ATTrackingManager
- Send consent for DMA compliance
- Sending SKAN postback to Appsflyer
- MacOS initialization
- Request Listeners (Optional)
Requires Unity 2023.1 or newer (raised from 2019.4) —
init/startand most other APIs are nowasync Awaitable/Awaitable<T>methods on the RPC bridge. See Installation.
Create a game object and add the following init code:
using AppsFlyerSDK;
using System;
public class AppsFlyerInit : MonoBehaviour
{
async void Start()
{
// Subscribe before registerSessionReadyListener() so the event can't fire before
// we're listening.
AppsFlyer.OnSessionReady += OnSessionReadyHandler;
await AppsFlyer.init("devkey", "appID");
await AppsFlyer.registerSessionReadyListener();
// start() is called from OnSessionReadyHandler below, once the SDK reports the
// session is ready - see "Session Ready Listener" below for why.
}
void OnSessionReadyHandler(object sender, EventArgs args)
{
AppsFlyer.OnSessionReady -= OnSessionReadyHandler;
AppsFlyer.start();
}
}Note:
- Make sure not to call destroy on the game object.
- Use
DontDestroyOnLoadto keep the object when loading a new scene.
registerSessionReadyListener() defers start() until the native SDK reports it has finished
evaluating session-readiness conditions (config validity, any pending deep link), rather than
racing start() against that evaluation. This is the recommended way to call start(); calling
AppsFlyer.start() directly right after init() still works but skips that coordination.
AppsFlyer.OnSessionReady += OnSessionReadyHandler; // subscribe first
await AppsFlyer.init(devKey, appID, this);
await AppsFlyer.registerSessionReadyListener();
void OnSessionReadyHandler(object sender, EventArgs args)
{
AppsFlyer.OnSessionReady -= OnSessionReadyHandler;
AppsFlyer.start();
}Unregister with AppsFlyer.unregisterSessionReadyListener() if you no longer need the callback.
AppsFlyer.isSessionReady() lets you poll the current state instead of subscribing to the
event.
Note (Android): on a cold, post-install launch, the native SDK's own foreground-detection can miss the app's very first
onResume()(it's registered byinit(), which — running from Unity's managed layer — is unavoidably a beat behind Android's real launch-triggeringonResume()). If your app relies onstart()firing immediately on first launch rather than on the next background/foreground cycle, account for this in your own Activity/init flow. iOS is not affected — its SDK re-evaluates readiness immediately if the app is already active at registration time.
Set your own unique customer user ID (CUID) and cross-reference it with the unique AppsFlyer ID.
- Appear in AppsFlyer raw data CSV reports.
- Can be used in postback APIs to cross-reference with internal IDs.
To set the CUID, use:
AppsFlyer.setCustomerUserId("someId");Good practice! Set the CUID early in the app flow—it is only associated with events reported after its setup.
- Recorded events will be associated with the CUID.
- Related data will appear in the raw data reports for installs and events..
If it’s important for you to associate the install event with the CUID, call setCustomerUserId before calling start.
- Add the
AppTrackingTransparencyframework to your xcode project. - In the
Info.plist:- Add an entry to the list: Press + next to
Information Property List. - Scroll down and select
Privacy - Tracking Usage Description. - Add as the value the wording you want to present to the user when asking for permission to collect the IDFA.
- Add an entry to the list: Press + next to
- Request the tracking authorization before calling
start(), and wait for the user's decision (or a timeout) so the first session can carry IDFA if the user grants it. There is no plugin API for this — request authorization yourself (e.g. via the com.unity.ads.ios-support package, or a small native call) and delaystart()until the request completes. SeeRequestATTThenStart()in the sample app'sQATestScript.csfor a reference implementation.using Unity.Advertisement.IosSupport; /* ... */ if (ATTrackingStatusBinding.GetAuthorizationTrackingStatus() == ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED) { ATTrackingStatusBinding.RequestAuthorizationTracking(); } // Wait for the authorization decision, then call start(). /* ... */
The ATT consent dialog can be customized by modifying your Xcode project's info.plist:
For detailed instructions, see Apple's documentation.
Unity SDK plugin offers two alternative methods for gathering consent data:
Through a Consent Management Platform (CMP): If the app uses a CMP that complies with the Transparency and Consent Framework (TCF) v2.2 protocol, the Unity SDK can automatically retrieve the consent details.
OR
Through a dedicated Unity SDK API: Developers can pass Google's required consent data directly to the Unity SDK using a specific API designed for this purpose.
-
Initialize the SDK.
-
Call enableTCFDataCollection(true) api before start() to instruct the SDK to collect the TCF data from the device.
-
Use the CMP to decide if you need the consent dialog in the current session to acquire the consent data. If you need the consent dialog move to step 4; otherwise move to step 5.
-
Get confirmation from the CMP that the user has made their consent decision and the data is available.
-
Call start().
await AppsFlyer.init(devKey, appID, this); AppsFlyer.enableTCFDataCollection(true); //YOUR_CMP_FLOW() // if already has consent ready - you can start await AppsFlyer.start(); //else Waiting for CMP completion and data ready and then start await AppsFlyer.start();
- Initialize the SDK.
- Determine whether the GDPR applies or not to the user.
-
Given that GDPR is applicable to the user, determine whether the consent data is already stored for this session. i. If there is no consent data stored, show the consent dialog to capture the user consent decision. ii. If there is consent data stored continue to the next step.
-
To transfer the consent data to the SDK create an AppsFlyerConsent object with the following parameters:
- hasConsentForDataUsage - Indicates whether the user has consented to use their data for advertising purposes.
- hasConsentForAdsPersonalization - Indicates whether the user has consented to use their data for personalized advertising.
-
Call setConsentData()with the AppsFlyerConsent object.
-
Call start().
// If the user is subject to GDPR - collect the consent data // or retrieve it from the storage ... // Set the consent data to the SDK: AppsFlyerConsent consent = new AppsFlyerConsent( isUserSubjectToGDPR: true, hasConsentForDataUsage: true, hasConsentForAdsPersonalization: true ); AppsFlyer.setConsentData(consent); await AppsFlyer.start();
-
Create an AppsFlyerConsent object with
isUserSubjectToGDPRset tofalse. The other consent fields can be omitted. -
Pass the AppsFlyerConsent object to setConsentData().
-
Call start().
// If the user is not subject to GDPR: AppsFlyerConsent consent = new AppsFlyerConsent(isUserSubjectToGDPR: false); AppsFlyer.setConsentData(consent); await AppsFlyer.start();
To test whether your SDK sends DMA consent data with each event, perform the following steps:
- Enable the SDK debug mode.
- Search for consent_data in the log of the outgoing request.
To register the AppsFlyer endpoint, you need to add the NSAdvertisingAttributionReportEndpoint key to your info.plist and set the value to https://appsflyer-skadnetwork.com/.
More info on how to update the info.plist can be found here.
- Use the manual integration code above, passing your MacOS app ID.
- Build for the platform
PC, Mac & Linux Standeloneand chooseMacOSas the target platform.
- Add the following code to the game object with the AppsFlyer init code (see Manual integration).
- Add the following code before start()
Sessions response example:
void Start()
{
AppsFlyer.OnRequestResponse += AppsFlyerOnRequestResponse;
await AppsFlyer.init(devKey, appID, this);
await AppsFlyer.start();
}
void AppsFlyerOnRequestResponse(object sender, EventArgs e)
{
var args = e as AppsFlyerRequestEventArgs;
AppsFlyer.AFLog("AppsFlyerOnRequestResponse", " status code " + args.statusCode);
}In-App response example:
void Start()
{
AppsFlyer.OnInAppResponse += (sender, args) =>
{
var af_args = args as AppsFlyerRequestEventArgs;
AppsFlyer.AFLog("AppsFlyerOnRequestResponse", " status code " + af_args.statusCode);
};
await AppsFlyer.init(devKey, appID, this);
await AppsFlyer.start();
}
| statusCode | errorDescription |
|---|---|
| 200 | null |
| 10 | "Event timeout. Check 'minTimeBetweenSessions' param" |
| 11 | "Skipping event because 'isStopTracking' enabled" |
| 40 | Network error: Error description comes from Android |
| 41 | "No dev key" |
| 50 | "Status code failure" + actual response code from the server |