> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appstack.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Unity

<Prompt description="Use Cursor, Claude Code, or another AI to help you integrate the Unity SDK." actions={["copy", "cursor"]}>
  You are an expert Unity engineer helping me integrate the Appstack Unity SDK into my game. You are running inside an IDE assistant such as Cursor or Claude Code and you can see my codebase.

  Use the reference below to fully wire the package. When I paste this prompt and share my Unity project files, you should:

  1. Provide the exact `Packages/manifest.json` (or Package Manager) steps required to install `com.appstack.unity-sdk` from OpenUPM, including the scoped registry entry.
  2. Tell me whether to use auto-initialization (**Edit → Project Settings → Appstack**) or manual `AppstackSDK.Configure(...)`, and generate idiomatic C# code for the manual path when it fits my bootstrap flow.
  3. Validate my iOS and Android player settings (minimum iOS version, min/target API level, Java version, EDM4U or manual Gradle dependency) against the documentation and highlight anything missing.
  4. Summarize the full checklist (install, platform setup, initialization, event tracking) so we can confirm that everything from the docs has been applied.

  ***

  ## Reference: Appstack Unity SDK

  **Requirements**

  * Unity: 6 (`6000.0`) or newer
  * iOS: 15.0+
  * Android: API level 21+, target API level 34+, Java 17+
  * Android builds need either External Dependency Manager for Unity (EDM4U) or the manual Gradle dependency setup. The Appstack package does not install EDM4U.

  **Installation (OpenUPM)**

  1. Add `https://package.openupm.com` as a scoped registry for `com.appstack`.
  2. In Unity, open **Window → Package Manager**.
  3. Select **+ → Add package by name** and enter `com.appstack.unity-sdk`.

  Or add the scoped registry and dependency directly to `Packages/manifest.json`:

  ```json theme={null}
  {
    "scopedRegistries": [
      {
        "name": "package.openupm.com",
        "url": "https://package.openupm.com",
        "scopes": ["com.appstack"]
      }
    ],
    "dependencies": {
      "com.appstack.unity-sdk": "1.2.0"
    }
  }
  ```

  Use the **current** version from [openupm.com/packages/com.appstack.unity-sdk](https://openupm.com/packages/com.appstack.unity-sdk/).

  **iOS configuration**

  * Set **Edit → Project Settings → Player → iOS → Target minimum iOS Version** to `15.0` or newer.
  * The iOS dependency is resolved automatically by the Unity build postprocessor. No manual Xcode framework setup is required.

  **Android configuration**

  Option 1 (recommended): install [EDM4U](https://github.com/googlesamples/unity-jar-resolver). Appstack's Android dependency is then resolved automatically. If automatic resolution is off, run **Assets → External Dependency Manager → Android Resolver → Resolve**.

  Option 2: add the repository and dependency manually to your Gradle templates:

  ```gradle theme={null}
  repositories {
      mavenCentral()
  }

  dependencies {
      implementation "tech.appstack.android-sdk:appstack-android-sdk:1.7.0"
  }
  ```

  No manual R8 or ProGuard configuration is required; Appstack adds its keep rules to the generated Android project automatically.

  **Automatic initialization (no code)**

  Open **Edit → Project Settings → Appstack**, select **Create Appstack Settings**, and enter the development and production API keys for each platform you ship. Appstack initializes before the first scene, without a GameObject or startup script. Installing the package alone creates no settings and changes no runtime behavior.

  **Manual initialization**

  ```csharp theme={null}
  using System.Collections.Generic;
  using Appstack;
  using UnityEngine;

  public sealed class AppstackInitializer : MonoBehaviour
  {
      [SerializeField] private string iosApiKey;
      [SerializeField] private string androidApiKey;

      private void Start()
      {
  #if UNITY_IOS && !UNITY_EDITOR
          string apiKey = iosApiKey;
  #elif UNITY_ANDROID && !UNITY_EDITOR
          string apiKey = androidApiKey;
  #else
          string apiKey = "your-api-key";
  #endif

          AppstackSDK.Configure(apiKey);

  #if UNITY_IOS && !UNITY_EDITOR
          AppstackSDK.EnableAppleAdsAttribution();
  #endif

          AppstackSDK.SendEvent(
              EventType.PURCHASE,
              parameters: new Dictionary<string, object>
              {
                  { "revenue", 29.99 },
                  { "currency", "USD" }
              });
      }
  }
  ```

  **Configuration parameters**

  ```csharp theme={null}
  AppstackSDK.Configure(
      apiKey: "your-platform-api-key",
      logLevel: 1,                      // 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR
      customerUserId: "optional-user-id"
  );
  ```

  **Customer user ID**

  ```csharp theme={null}
  AppstackSDK.SetCustomerUserId("user-123"); // on login
  ```

  **Sending events**

  ```csharp theme={null}
  // Standard events
  AppstackSDK.SendEvent(EventType.SIGN_UP);
  AppstackSDK.SendEvent(EventType.LEVEL_COMPLETE);

  // With parameters (including revenue)
  AppstackSDK.SendEvent(EventType.PURCHASE, parameters: new Dictionary<string, object>
  {
      { "revenue", 29.99 },
      { "currency", "USD" }
  });

  // Custom events
  AppstackSDK.SendEvent(
      EventType.CUSTOM,
      eventName: "user_attributes",
      parameters: new Dictionary<string, object>
      {
          { "email", "test@example.com" },
          { "name", "John Doe" },
          { "phone_number", "+33060000000" },
          { "date_of_birth", "2026-02-01" }
      });
  ```

  **EventType values (recommended standard events):**

  * Authentication: `EventType.LOGIN`, `EventType.SIGN_UP`, `EventType.REGISTER`
  * Monetization: `EventType.PURCHASE`, `EventType.ADD_TO_CART`, `EventType.ADD_TO_WISHLIST`, `EventType.INITIATE_CHECKOUT`, `EventType.START_TRIAL`, `EventType.SUBSCRIBE`
  * Games: `EventType.LEVEL_START`, `EventType.LEVEL_COMPLETE`
  * Engagement: `EventType.TUTORIAL_COMPLETE`, `EventType.SEARCH`, `EventType.VIEW_ITEM`, `EventType.VIEW_CONTENT`, `EventType.SHARE`
  * Custom: `EventType.CUSTOM` (requires `eventName`)

  `EventType.INSTALL` is emitted automatically by the native SDKs; `SendEvent(EventType.INSTALL)` is a no-op.

  **Enhanced app campaigns**

  * For revenue events, send:
    * `revenue` or `price` (number)
    * `currency` (e.g. `EUR`, `USD`)
  * To improve Meta matching, include when possible:
    * `email`
    * `name` (first + last name)
    * `phone_number` (also accepted as `phone` or `phoneNumber`)
    * `date_of_birth` (`YYYY-MM-DD`; also accepted as `birthdate`, `birthday`, or `dateOfBirth`)
    * `gender`
  * Appstack automatically encrypts these matching parameters before using them for attribution matching.
</Prompt>

## **Repository**

Here, you will find the [Appstack Unity SDK repository](https://github.com/appstack-tech/appstack-unity-sdk) and the [OpenUPM package page](https://openupm.com/packages/com.appstack.unity-sdk/). Please use the latest available version of the SDK.

## **Quickstart**

Use this path when you only need the minimum production integration:

1. Add `https://package.openupm.com` as a scoped registry for `com.appstack`, then add `com.appstack.unity-sdk` from the Unity Package Manager.
2. Install EDM4U so the Android native dependency resolves automatically, and set the minimum iOS version to 15.0.
3. Copy the **Production** API key from **SDK** in Appstack, for each platform you ship.
4. Open **Edit → Project Settings → Appstack**, select **Create Appstack Settings**, and paste the keys — or call `AppstackSDK.Configure(...)` once at startup instead.
5. Send standard events such as `EventType.LOGIN`, `EventType.SIGN_UP`, `EventType.PURCHASE`, and `EventType.SUBSCRIBE`.
6. Confirm events appear in the Appstack SDK page before enabling downstream integrations.

```csharp theme={null}
using System.Collections.Generic;
using Appstack;

#if UNITY_IOS && !UNITY_EDITOR
    string apiKey = "your-ios-production-api-key";
#elif UNITY_ANDROID && !UNITY_EDITOR
    string apiKey = "your-android-production-api-key";
#else
    string apiKey = "your-api-key"; // Editor or fallback
#endif

AppstackSDK.Configure(apiKey);

AppstackSDK.SendEvent(EventType.PURCHASE, parameters: new Dictionary<string, object>
{
    { "revenue", 29.99 },
    { "currency", "USD" }
});
```

## **Requirements**

### **iOS**

* **iOS version:** 15.0+
* **Target minimum iOS Version** in **Player → iOS** must be `15.0` or newer.

### **Android**

* **Minimum API level:** 21 (Android 5.0).
* **Target API level:** 34+
* **Java:** 17+
* **Native dependency:** EDM4U (recommended) or the manual Gradle setup.

### **General**

* **Unity:** 6 (`6000.0`) or newer.

## **Initial setup**

<Steps>
  <Step title="Installation">
    **OpenUPM (recommended)**

    1. Add `https://package.openupm.com` as a scoped registry for `com.appstack`.
    2. In Unity, open **Window → Package Manager**.
    3. Select **+ → Add package by name** and enter `com.appstack.unity-sdk`.

    See the [OpenUPM getting-started guide](https://openupm.com/docs/getting-started.html) for scoped-registry instructions, or edit `Packages/manifest.json` directly:

    ```json theme={null}
    {
      "scopedRegistries": [
        {
          "name": "package.openupm.com",
          "url": "https://package.openupm.com",
          "scopes": ["com.appstack"]
        }
      ],
      "dependencies": {
        "com.appstack.unity-sdk": "1.2.0"
      }
    }
    ```

    Use the **current** version from the [OpenUPM package page](https://openupm.com/packages/com.appstack.unity-sdk/).

    **iOS Configuration**

    1. Open **Edit → Project Settings → Player → iOS**.
    2. Set **Target minimum iOS Version** to `15.0` or newer.
    3. Build the iOS player normally.

    **Note:** Appstack resolves its iOS dependency automatically during the Unity build and embeds the framework in the application. No manual Xcode framework or Apple system-framework configuration is required.

    **Android Configuration**

    The Unity package contains the Appstack C# and JNI bridge code, but it does not bundle the native Appstack Android SDK. Choose one of the following before building for Android.

    *Option 1 (recommended): EDM4U*

    Install [External Dependency Manager for Unity (EDM4U)](https://github.com/googlesamples/unity-jar-resolver). Appstack's Android dependency declaration is then discovered and resolved automatically. The Appstack Unity package does not install EDM4U for you. If automatic resolution is disabled, run **Assets → External Dependency Manager → Android Resolver → Resolve**.

    *Option 2: manual Gradle configuration*

    Add the following repository and dependency to the Gradle templates used by your Unity project:

    ```gradle theme={null}
    repositories {
        mavenCentral()
    }

    dependencies {
        implementation "tech.appstack.android-sdk:appstack-android-sdk:1.7.0"
    }
    ```

    The dependency must be available to the `unityLibrary` module that compiles Android plugins.

    **Minification:** no manual R8 or ProGuard configuration is required. Appstack adds its bridge keep rules to the generated Android project automatically, and the native SDK provides its own consumer rules. You do not need to enable Unity's **Custom Proguard File** setting for Appstack.
  </Step>

  <Step title="Initialization">
    Follow these steps to get the API key:

    1. In Appstack, from the side menu, select **SDK** and ensure you are selecting the correct application.
    2. Select the **Production** environment.
    3. Copy the **API key**.

    Repeat for each platform you ship, and for the **Development** environment if you want separate keys for development builds.

    **Automatic initialization (no code)**

    Open **Edit → Project Settings → Appstack**, select **Create Appstack Settings**, and enter the development and production API keys for each platform. Appstack initializes before the first scene loads, without requiring a GameObject or startup script.

    * **Auto Initialize** — turn auto-initialization on or off.
    * **Environment** — `Automatic` uses the development key for Unity Development Builds and the production key for other builds. `Development` and `Production` pin every build to that environment.
    * **Allow Production Fallback** — lets a development build use its production key when no development key is configured. Off by default. Production builds never fall back to a development key.
    * **Log Level** — `0=DEBUG`, `1=INFO`, `2=WARN`, `3=ERROR`.
    * **Enable iOS** / **Enable Android** — enable each platform independently, each with its own **Development API Key** and **Production API Key**.
    * **Enable Apple Ads Attribution** — enables Apple Ads attribution as part of iOS auto-initialization.

    Only the current build target is validated: an iOS build does not require Android keys. A build fails only when auto-initialization and its current target platform are enabled but no key can be resolved for that build, so the app never ships with Appstack unexpectedly disabled.

    <Note>
      Creating settings opts the project into auto-initialization. Installing the package alone creates no settings and changes no runtime behavior.
    </Note>

    **Manual initialization**

    Leave the settings asset absent, or turn off **Auto Initialize**, when a consent flow, a custom bootstrap order, or remotely supplied configuration must come first. Call `Configure` once during application startup and before any other SDK method:

    ```csharp theme={null}
    using System.Collections.Generic;
    using Appstack;
    using UnityEngine;

    public sealed class AppstackInitializer : MonoBehaviour
    {
        [SerializeField] private string iosApiKey;
        [SerializeField] private string androidApiKey;

        private void Start()
        {
    #if UNITY_IOS && !UNITY_EDITOR
            string apiKey = iosApiKey;
    #elif UNITY_ANDROID && !UNITY_EDITOR
            string apiKey = androidApiKey;
    #else
            string apiKey = "your-api-key";
    #endif

            AppstackSDK.Configure(apiKey);

    #if UNITY_IOS && !UNITY_EDITOR
            AppstackSDK.EnableAppleAdsAttribution();
    #endif

            AppstackSDK.SendEvent(
                EventType.PURCHASE,
                parameters: new Dictionary<string, object>
                {
                    { "revenue", 29.99 },
                    { "currency", "USD" }
                });
        }
    }
    ```

    The first successful automatic or manual configuration wins. Repeating the same configuration is a silent no-op; a conflicting repeat is ignored with a warning that does not expose either API key. A failed configuration attempt does not lock the wrapper and can be retried.
  </Step>

  <Step title="Configuration parameters" stepNumber={3}>
    Initializes the SDK with your API key. Call it once during application startup, before any other SDK method.

    **Parameters:**

    * `apiKey` Your platform-specific API key from the Appstack dashboard.
    * `logLevel` Optional log level: 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR (default: 1). iOS has no dedicated warning level, so `WARN` behaves like `ERROR` there.
    * `customerUserId` Optional customer user ID.

    **Example:**

    ```csharp theme={null}
    AppstackSDK.Configure("your-api-key-here");

    // With all parameters
    AppstackSDK.Configure(
        apiKey: "your-api-key-here",
        logLevel: 0,                 // DEBUG
        customerUserId: "user-123"
    );
    ```

    You can check whether the SDK ended up disabled (for example after an invalid API key):

    ```csharp theme={null}
    if (AppstackSDK.IsSdkDisabled())
        Debug.LogWarning("Appstack SDK is disabled – check your API key.");
    ```
  </Step>

  <Step title="Customer user ID" stepNumber={4}>
    The customer user ID is your own identifier for the signed-in user. Appstack attaches it to events so server-to-server events — which identify the user by this ID rather than by the install — can be joined back to the install that produced them.

    Pass it to `Configure` when you already know it at startup. More often a login reveals it afterwards, so set it whenever it becomes known:

    ```csharp theme={null}
    AppstackSDK.SetCustomerUserId("user-123"); // on login
    ```

    * Callable at any time, before or after `Configure`, as often as you like. The last call wins, and it applies to every event sent from then on, including ones the native SDK has buffered but not yet flushed.
    * The call does not send anything by itself: make sure at least one event follows, or no mapping is ever formed.
    * Calling `Configure` again to change the ID does not work — a repeat `Configure` is a no-op and its `customerUserId` is ignored.
  </Step>

  <Step title="Sending events" stepNumber={5}>
    Track user actions and revenue from your scripts:

    ```csharp theme={null}
    // Track events without parameters
    AppstackSDK.SendEvent(EventType.SIGN_UP);
    AppstackSDK.SendEvent(EventType.LEVEL_COMPLETE);

    // Track events with parameters (including revenue)
    AppstackSDK.SendEvent(EventType.PURCHASE, parameters: new Dictionary<string, object>
    {
        { "revenue", 29.99 },
        { "currency", "USD" }
    });
    AppstackSDK.SendEvent(EventType.SUBSCRIBE, parameters: new Dictionary<string, object>
    {
        { "revenue", 9.99 },
        { "plan", "monthly" }
    });

    // Custom events
    AppstackSDK.SendEvent(
        EventType.CUSTOM,
        eventName: "user_attributes",
        parameters: new Dictionary<string, object>
        {
            { "email", "test@example.com" },
            { "name", "John Doe" },
            { "phone_number", "+33060000000" },
            { "date_of_birth", "2026-02-01" }
        });
    ```

    **Available EventType values**

    It is recommended to use standard events for a smoother experience.

    <Note>
      `EventType.INSTALL` is tracked automatically by the native SDKs on first launch. Do not send it manually — `SendEvent(EventType.INSTALL)` is a no-op.
    </Note>

    * `EventType.LOGIN`/ `EventType.SIGN_UP`/ `EventType.REGISTER` Authentication
    * `EventType.PURCHASE`/ `EventType.ADD_TO_CART`/ `EventType.ADD_TO_WISHLIST`/ `EventType.INITIATE_CHECKOUT`/ `EventType.START_TRIAL`/ `EventType.SUBSCRIBE` Monetization
    * `EventType.LEVEL_START`/ `EventType.LEVEL_COMPLETE` Game progression
    * `EventType.TUTORIAL_COMPLETE`/ `EventType.SEARCH`/ `EventType.VIEW_ITEM`/ `EventType.VIEW_CONTENT`/ `EventType.SHARE` Engagement
    * `EventType.CUSTOM` For application-specific events

    Tracks standard and custom events with optional parameters:

    * `eventType` - Event type from the `EventType` enum (required).
    * `eventName` - Event name required for `CUSTOM` events; ignored for standard events.
    * `parameters` - Optional dictionary of parameters (e.g. `{ "revenue", 29.99 }`, `{ "currency", "USD" }`).

    Event parameters may contain strings, Booleans, finite numeric values, nulls, nested string-keyed dictionaries, and arrays. Unsupported objects and non-finite numbers such as `NaN` or infinity throw an `ArgumentException` before the event is sent.

    **Enhanced app campaigns**

    <Tip>
      When running enhanced app campaigns (EACs), it is highly recommended to send multiple parameters with the in-app event to improve matching quality.
    </Tip>

    For any event that represents revenue, we recommend sending:

    1. `revenue` or `price` (number).
    2. `currency`(string, e.g. `EUR`, `USD`).

    ```csharp theme={null}
    AppstackSDK.SendEvent(EventType.PURCHASE, parameters: new Dictionary<string, object>
    {
        { "revenue", 4.99 },
        { "currency", "EUR" }
    });
    ```

    To improve matching quality on Meta, send events including the following parameters if you can fulfill them. Appstack automatically encrypts these matching parameters before using them for attribution matching.

    1. `email`.
    2. `name` (first + last name in the same field).
    3. `phone_number` — also accepted as `phone` or `phoneNumber`.
    4. `date_of_birth` (recommended format: `YYYY-MM-DD`) — also accepted as `birthdate`, `birthday`, or `dateOfBirth`.
    5. `gender`.
  </Step>
</Steps>

## **Appstack ID and attribution params**

After configuration, you can read the Appstack user ID and the attribution parameters, so you can forward them to any partner SDK that accepts attribution data.

```csharp theme={null}
string appstackId = AppstackSDK.GetAppstackId();

AppstackSDK.GetAttributionParams(
    onSuccess: parameters =>
    {
        foreach (var kv in parameters)
            Debug.Log($"Attribution: {kv.Key} = {kv.Value}");
    },
    onError: error => Debug.LogError($"Attribution error: {error}")
);
```

* **`GetAppstackId()`** — Appstack user identifier when a partner expects `$appstackId` or similar.
* **`GetAttributionParams(onSuccess, onError)`** — Attribution payload (campaign, media source, click IDs, device identifiers where available) to forward to partners.

Callbacks are delivered on the synchronization context captured when `GetAttributionParams` is called, when one is available. Calling it from Unity's main thread lets the callbacks safely update Unity objects.

## **Development setup**

### **Environment-based configuration**

With auto-initialization, keep **Environment** on `Automatic`: Unity Development Builds use the development key and other builds use the production key. For manual initialization, resolve the key yourself:

```csharp theme={null}
#if UNITY_IOS && !UNITY_EDITOR
    string apiKey = Debug.isDebugBuild ? "ios-development-key" : "ios-production-key";
#elif UNITY_ANDROID && !UNITY_EDITOR
    string apiKey = Debug.isDebugBuild ? "android-development-key" : "android-production-key";
#else
    string apiKey = "your-api-key"; // Editor or fallback
#endif

AppstackSDK.Configure(apiKey, logLevel: Debug.isDebugBuild ? 0 : 1);
```

### **Editor and unsupported platforms**

In the Unity Editor and on non-iOS/Android platforms, SDK methods are no-ops or return safe defaults: `GetAppstackId()` returns `null` and `IsSdkDisabled()` returns `true`. These platforms do not call native code, so verify your integration on a device or in a store build.

## **Platform-specific considerations**

### **iOS**

**Apple Ads attribution:**

* Requires iOS 15.0+ and an App Store or TestFlight installation.
* Attribution data appears within 24-48 hours.
* User consent may be required for detailed attribution.
* Simulator and ordinary development installs do not represent the production attribution flow.

```csharp theme={null}
#if UNITY_IOS && !UNITY_EDITOR
AppstackSDK.EnableAppleAdsAttribution();
#endif
```

With auto-initialization, enable **Enable Apple Ads Attribution** in **Edit → Project Settings → Appstack** instead of calling the method yourself.

### **Android**

**Play Store Attribution**

* Install referrer data collected automatically.
* Attribution available immediately for Play Store installs.
* Works with Android 5.0+ (API level 21).

## **Security and privacy**

* Never commit API keys to version control. The password fields in **Project Settings → Appstack** mask keys visually only: values stay plaintext in the settings asset and in version control.
* Unity includes the entire `Resources` asset in player builds, so every configured key — including development keys and keys for the other mobile platform — may be present in a production player. Treat them as application ingestion credentials, not administrative secrets.
* Use separate production and development keys.
* Do not put personally identifiable information in event names.
* Only send matching parameters such as `email`, `name`, `phone_number`, and `date_of_birth` when your app has the right consent and compliance basis. Appstack automatically encrypts these fields before using them for attribution matching.
* Prefer standard event types for common flows so event mapping remains consistent across Appstack and ad integrations.

## **Limitations**

### **Attribution timing**

* **iOS:** Apple Ads attribution data appears within 24-48 hours after install.
* **Android:** Install referrer data available immediately for Play Store installs.
* Attribution only available for apps installed from official stores.

### **Platform constraints**

* **Unity:** 6 (`6000.0`) or newer.
* **iOS:** requires iOS 15.0+.
* **Android:** minimum API level 21, target API level 34+, Java 17+.
* Android builds require EDM4U or the manual Gradle dependency; the package does not bundle the native Android SDK.
* SDK methods are no-ops in the Editor and on non-iOS/Android platforms.

### **Event tracking**

* Event names are case-sensitive and standardized.
* For revenue events, always pass a `revenue` (or `price`) and a `currency` parameter.
* The SDK must be configured — automatically or manually — before any tracking call.
* `SendEvent(EventType.INSTALL)` is ignored; install is tracked automatically.
* `EnableAppleAdsAttribution()` only applies on iOS and is a no-op on Android.
* Custom events require an `eventName`; unsupported parameter values throw an `ArgumentException` before the event is sent.
* Network connectivity required for event transmission (events are queued offline).

## **Troubleshooting**

### **Configuration fails**

* Confirm the API key was copied from the correct app and environment in Appstack.
* Confirm `AppstackSDK.Configure(...)` runs once at startup before any other SDK method, or that auto-initialization settings exist with a key for the current target and environment.
* Check `AppstackSDK.IsSdkDisabled()` and the Unity Console with `logLevel: 0` (DEBUG).
* Remember that a repeat `Configure` is ignored, so a second call cannot change the API key, log level, or customer user ID.

### **Events do not appear**

* Confirm the build runs on a device: SDK methods are no-ops in the Editor.
* Confirm configuration completed before the first `SendEvent(...)` call.
* Confirm the device has network connectivity.
* Check that revenue events include a numeric `revenue` or `price` value and a valid `currency`.
* Allow a few minutes for events to appear in the dashboard.

### **iOS build cannot find `AppstackSDK`**

* Delete the generated Xcode project and export it again from Unity.
* Check the Unity Console for postprocessing errors.
* Confirm the generated Xcode project lists the `AppstackSDK` package product on both the `UnityFramework` and application targets.
* Confirm the build machine can reach GitHub to resolve Swift packages.

### **Gradle cannot resolve the Appstack Android SDK**

* Run **Assets → External Dependency Manager → Android Resolver → Resolve** again.
* Confirm Maven Central is available in the generated Gradle repositories.
* Confirm the build uses Java 17 or newer.
* Inspect the Unity Console and Gradle output for the original resolution error.

### **A build fails with an Appstack configuration error**

* Auto-initialization is enabled for the current target platform but no key resolves for that build. Add the missing key in **Edit → Project Settings → Appstack**, disable that platform, or turn off **Auto Initialize**.
* For a development build with only a production key, either add a development key or enable **Allow Production Fallback**.

## **Apple Ads**

To start using the Apple Ads integration, [click here](/Integrations/apple-ads) to see the correct SDK documentation.

## **Verification checklist**

* `com.appstack.unity-sdk` is installed from OpenUPM at a current version.
* Project meets Unity 6+, iOS 15.0+, Android API level 21+ / target 34+, and Java 17+ requirements.
* **Target minimum iOS Version** is set to 15.0 or newer.
* EDM4U is installed and resolved, or the manual Gradle dependency is configured for the `unityLibrary` module.
* Platform-specific API keys are configured for iOS and Android.
* Production API keys are used in production builds; development keys only in development builds.
* The SDK is configured exactly once — through auto-initialization settings or a single `Configure(...)` at startup.
* iOS-only Apple Ads calls are guarded with `#if UNITY_IOS && !UNITY_EDITOR`, or enabled through the settings asset.
* `EventType.INSTALL` is not sent manually.
* Login, signup, purchase, subscription, and other key app events use standard event types where possible.
* Revenue events include `revenue` or `price` and `currency`.
* Custom events use `EventType.CUSTOM` with a descriptive `eventName`.
* The customer user ID is set once it becomes known, with at least one event following.
* Appstack ID and attribution params are available before wiring partner integrations.
* Events are visible in the Appstack SDK page before launch.

## **Support**

For questions or issues:

1. Check the [GitHub Repository](https://github.com/appstack-tech/appstack-unity-sdk).
2. Contact our support team at [support@appstack.tech](mailto:support@appstack.tech)
3. Open an issue in the repository.

<Prompt description="Use Cursor, Claude Code, or another AI to validate your existing Appstack Unity SDK integration." actions={["copy", "cursor"]}>
  You are an expert Unity engineer reviewing my existing Appstack Unity SDK integration. You are running inside an IDE assistant such as Cursor or Claude Code and you can see my C# scripts and Unity project settings.

  Your goal is to **validate that my integration fully matches the official Unity SDK documentation** and identify any missing or incorrect steps. When I paste this prompt and share my project files, you should:

  1. **Package & environment**
     * Inspect `Packages/manifest.json` to confirm:
       * The `com.appstack` scoped registry points at `https://package.openupm.com`.
       * `com.appstack.unity-sdk` is present at a **current** version (check the OpenUPM package page rather than assuming a fixed version).
       * The Unity Editor version is 6 (`6000.0`) or newer.
     * Suggest the exact manifest or Package Manager steps needed if something is out of spec.

  2. **iOS configuration**
     * Check that **Target minimum iOS Version** is `15.0` or newer in the iOS player settings.
     * Note that the iOS dependency resolves automatically through the Unity Xcode postprocessor, and flag anything in my project (custom postprocessors, manual framework wiring) that could conflict with it.

  3. **Android configuration**
     * Verify min API level 21+, target API level 34+, and a Java 17+ toolchain.
     * Confirm either EDM4U is installed and resolved, or my Gradle templates add Maven Central and `tech.appstack.android-sdk:appstack-android-sdk` to the `unityLibrary` module.
     * Note that no manual R8/ProGuard keep rules are needed, and flag any custom Proguard configuration that strips the Appstack bridge.

  4. **SDK initialization (C#)**
     * Determine whether I use auto-initialization (an `AppstackSettings` asset under `Assets/Appstack/Resources`) or manual `AppstackSDK.Configure(...)`, and verify I am not doing both in conflicting ways.
     * For auto-initialization, review the settings: per-platform enablement, environment mode, **Allow Production Fallback**, log level, and Apple Ads attribution.
     * For manual initialization, verify `Configure(...)` runs once at startup before any other SDK method, that platform keys are selected with `#if UNITY_IOS` / `#if UNITY_ANDROID`, and that no code relies on a repeat `Configure` to change the key, log level, or customer user ID.
     * Propose idiomatic C# initialization code if my current setup is missing, duplicated, or fragile.

  5. **Customer user ID**
     * Check that `SetCustomerUserId(...)` is called when a login reveals the ID, and that at least one event follows.
     * Flag any attempt to change the ID by calling `Configure` again.

  6. **Event tracking implementation**
     * Find all `AppstackSDK.SendEvent(...)` calls and verify:
       * Standard `EventType` values are used where appropriate (`PURCHASE`, `SIGN_UP`, `SUBSCRIBE`, `LEVEL_COMPLETE`, etc.).
       * Revenue events send `revenue` (or `price`) and `currency` in the parameters dictionary.
       * Custom events use `EventType.CUSTOM` with a descriptive `eventName` and, for EAC / Meta, rich attributes such as `email`, `name`, `phone_number`, and `date_of_birth`, noting that Appstack automatically encrypts these matching parameters before using them for attribution matching.
       * Parameter values are JSON-representable — no non-finite numbers or unsupported object types that would throw `ArgumentException`.
       * `EventType.INSTALL` is never sent manually.
     * Highlight missing or inconsistent event usage and suggest concrete `SendEvent` calls that fit my game's flows.

  7. **Platform-specific behavior & limitations**
     * Validate that `EnableAppleAdsAttribution()` is only called on iOS device builds (or enabled through the settings asset).
     * Confirm my code tolerates Editor and unsupported platforms, where methods are no-ops, `GetAppstackId()` returns `null`, and `IsSdkDisabled()` returns `true`.
     * Check that `GetAttributionParams(...)` is called from the main thread when its callbacks touch Unity objects.
     * Respect documented limitations around attribution timing and official store installs.

  8. **Validation report & checklist**
     * Produce a clear summary of:
       * What is correctly implemented and safe to ship.
       * What is missing, misconfigured, or risky, with specific C# file and project-setting changes.
</Prompt>
