# Unity v0.x → v1.0 Migration Guide

Airflux Unity SDK v1.0 introduces a redesigned API surface and updated data taxonomy for more accurate event/context aggregation and inference decisions. This guide explains how to migrate an existing Unity v0.x (including v0.1) integration to v1.0 safely.

{% hint style="warning" %}
Deprecated: Unity v0.x is a legacy integration. New integrations should use the [Airflux Integration (Unity)](/airflux-onboarding/airflux-integration-unity.md) guide.
{% endhint %}

***

#### Important notes before you migrate

> **Attention: Breaking change**\
> Airflux Unity SDK v1.0 is **not backward-compatible** with v0.x.
>
> * You **must** update your code to the new APIs and taxonomy.
> * You **must not** keep v0.x and v1.0 installed in the same Unity project.

> **Attention: Data reset**\
> When upgrading to v1.0, existing on-device Airflux data (stored context, counters, and any pending SDK data) should be treated as **reset**.\
> Plan your QA and roll-out assuming a clean slate for v1.0 devices.

#### Migration checklist

* [ ] Remove Airflux Unity SDK v0.x from the project
* [ ] Import Airflux Unity SDK v1.0 and reconfigure **Airflux Settings**
* [ ] Remove legacy **session tracking** calls (`NotifyAppForeground/NotifyAppBackground`)
* [ ] Replace v0.x APIs with v1.0 APIs (`SetUser`, `SetContext`, `RequestInference`)
* [ ] Update event taxonomy (especially **stage** and **ad impression** tracking)
* [ ] Verify logs, event payloads, and inference callback handling
* [ ] Run QA on Android & iOS builds and deploy

***

### 1. Update the SDK package

#### 1.1 Remove Airflux Unity SDK v0.x

1. In your Unity project, **delete the existing Airflux v0.x SDK files** (for example, the old `Assets/Airflux` folder and any related plugin files).
2. Confirm there is **no remaining v0.x assembly** or duplicated Airflux code in:
   * `Assets/Plugins/Android`
   * `Assets/Plugins/iOS`
   * `Assets/` (any legacy Airflux folders)

> **Attention**\
> Importing v1.0 without fully removing v0.x can cause compilation conflicts and duplicated classes.

#### 1.2 Install Airflux Unity SDK v1.0

1. Download the latest Airflux Unity SDK v1.0 `.unitypackage`. ([link](/airflux-onboarding/airflux-integration-unity/2.-install-the-airflux-sdk.md))
2. Import it via **Assets → Import Package → Custom Package…**
3. After import, open **Airflux → Airflux Settings** and configure:
   * **App Name** (required)
   * **App Token** (required)
   * **SDK Enabled / Auto Start Tracking Enabled** (optional, depending on consent flow)
   * **Allow Every Country Enabled / Country Allowlist** (optional but strongly recommended to confirm)
   * **Log Level** (recommend `debug` during QA)
   * **Session Timeout** (default 300 seconds)

These options are available in the v1.0 initialization settings.

***

### 2. Remove legacy session tracking (v0.x → v1.0)

In Unity v0.x, you typically implemented session tracking manually by calling `NotifyAppForeground()` / `NotifyAppBackground()` on app lifecycle callbacks.

In v1.0, the SDK automatically tracks app lifecycle events, so you **do not need** this manual wiring.

#### What to change

**Before (v0.x)**

```csharp
using UnityEngine;

public class AirfluxBehaviour : MonoBehaviour
{
    void OnApplicationPause(bool pauseStatus)
    {
        if (pauseStatus)
        {
            Airflux.NotifyAppBackground();
        }
        else
        {
            Airflux.NotifyAppForeground();
        }
    }
}
```

**After (v1.0)**\
Remove the `NotifyAppForeground/NotifyAppBackground` calls entirely.

```csharp
using UnityEngine;

public class AirfluxBehaviour : MonoBehaviour
{
    void OnApplicationPause(bool pauseStatus)
    {
        // No manual Airflux session tracking required in v1.0
    }
}
```

***

### 3. Migrate player attribute APIs (User & Context)

v1.0 consolidates “player attribute data” into:

* **User**: `Airflux.SetUser(...)`
* **Context**: `Airflux.SetContext(...)`

(These values are transmitted when you track an event or request an inference—set them **before** calling inference or tracking key events.)

#### 3.1 API mapping (v0.x → v1.0)

| What you were doing                       | v0.x API                            | v1.0 API                                                  |
| ----------------------------------------- | ----------------------------------- | --------------------------------------------------------- |
| Set User ID                               | `SetUserID(id)`                     | `SetUser(AirfluxUser.ID, id)`                             |
| Clear User ID                             | `ClearUserID()`                     | `ClearUser(AirfluxUser.ID)`                               |
| Set Level                                 | `SetLevel(level)`                   | `SetContext(AirfluxContext.LEVEL, level)`                 |
| Set Hard Currency                         | `SetHardCurrency(name, balance)`    | `SetContext(AirfluxContext.HARD_CURRENCY, name, balance)` |
| Set Soft Currency                         | `SetSoftCurrency(name, balance)`    | `SetContext(AirfluxContext.SOFT_CURRENCY, name, balance)` |
| Set “inference attributes” / custom state | `SetInferenceAttribute(key, value)` | `SetContext(AirfluxContext.ATTRIBUTE, key, value)`        |

> **Attention**\
> In v1.0, “inference attributes” are modeled as a **context category** (`AirfluxContext.ATTRIBUTE`).\
> If you used `SetInferenceAttribute(...)` in v0.x for things like `battlePass`, migrate them to `SetContext(AirfluxContext.ATTRIBUTE, ...)`.

#### 3.2 Example: User ID

**Before (v0.x)**

```csharp
Airflux.SetUserID("your_user_id");
```

**After (v1.0)**

```csharp
Airflux.SetUser(AirfluxUser.ID, "your_user_id");
```

#### 3.3 Example: Level & Currency

**After (v1.0)**

```csharp
// Level
Airflux.SetContext(AirfluxContext.LEVEL, 10);

// Currency
Airflux.SetContext(AirfluxContext.HARD_CURRENCY, "gem", 500);
Airflux.SetContext(AirfluxContext.SOFT_CURRENCY, "gold", 54000);

// Custom attributes
Airflux.SetContext(AirfluxContext.ATTRIBUTE, "battlePass", "premium");
```

***

### 4. Update event tracking (taxonomy changes)

The `TrackEvent(category, semanticAttributes, customAttributes)` signature remains conceptually the same, but **what you put into semantic vs custom attributes—and which events you should send—has changed in v1.0**.

Below are the most important migration points.

{% hint style="warning" %}
Important: It is essential to consult the [Airflux Integration (Unity](/airflux-onboarding/airflux-integration-unity/3.-send-in-game-event-data.md)) section regarding all required fields.
{% endhint %}

#### 4.1 Ad Impression: move `adType` and key fields into semantic attributes

In v0.x, `adType` was sent as a **custom attribute** (e.g., `customAttributes.adType`).

In v1.0, `AD_TYPE`, `AD_PLACEMENT_*`, `STAGE_*`, etc. are tracked as **semantic attributes** using `AirfluxAttribute.*`.

**After (v1.0) example**

```csharp
Airflux.TrackEvent(
    category: AirfluxCategory.AD_IMPRESSION,
    semanticAttributes: new Dictionary<string, object>
    {
        { AirfluxAttribute.VALUE, 0.025 },
        { AirfluxAttribute.CURRENCY, "USD" },

        // moved into semantic attributes in v1.0
        { AirfluxAttribute.AD_TYPE, "rewarded_ad" },              // or "interstitial_ad"
        { AirfluxAttribute.AD_PLACEMENT_ID, "stage_clear_reward" },

        // collect if available
        { AirfluxAttribute.STAGE_TYPE, "primary_stage" },
        { AirfluxAttribute.STAGE, 15 },
    }
);
```

> **Attention: Allowed values changed**\
> v1.0 requires pre-defined strings for many fields (e.g., `adType`, `stageType`, `stageResult`). Make sure your old values are mapped to the v1.0 allowed set.

#### 4.2 Stage tracking: replace “stage end via ACHIEVE\_LEVEL” with START\_STAGE / FINISH\_STAGE

In v0.x, some integrations used `ACHIEVE_LEVEL` to represent stage completion (with stage info and result).\
In v1.0, stage progression is tracked explicitly with:

* `START_STAGE`
* `FINISH_STAGE`

And `ACHIEVE_LEVEL` is used for actual level progression (if your game has a level system).

**After (v1.0) examples**

```csharp
// Stage start
Airflux.TrackEvent(
    category: AirfluxCategory.START_STAGE,
    semanticAttributes: new Dictionary<string, object>
    {
        { AirfluxAttribute.STAGE_TYPE, "primary_stage" },
        { AirfluxAttribute.STAGE, 10 }
    }
);

// Stage finish
Airflux.TrackEvent(
    category: AirfluxCategory.FINISH_STAGE,
    semanticAttributes: new Dictionary<string, object>
    {
        { AirfluxAttribute.STAGE_TYPE, "primary_stage" },
        { AirfluxAttribute.STAGE, 10 },
        { AirfluxAttribute.TOTAL_FINISHED_STAGE, 10 },
        { AirfluxAttribute.STAGE_RESULT, "success" } // success/fail/giveup/retry/draw/exhausted
    }
);
```

#### 4.3 Spend Credits: use `CREDIT_*` fields

v1.0 standardizes currency spending into `SPEND_CREDITS` with semantic attributes:

```csharp
Airflux.TrackEvent(
    category: AirfluxCategory.SPEND_CREDITS,
    semanticAttributes: new Dictionary<string, object>
    {
        { AirfluxAttribute.CREDIT_CLASS, "hard" },    // "hard" or "soft"
        { AirfluxAttribute.CREDIT_TYPE, "coin" },
        { AirfluxAttribute.CREDIT_SPENT, 10 },
        { AirfluxAttribute.CREDIT_CURRENT, 990 },

        // stage info if available
        { AirfluxAttribute.STAGE_TYPE, "primary_stage" },
        { AirfluxAttribute.STAGE, 10 }
    }
);
```

#### 4.4 Order Completed: send product list and purchase route

v1.0 expects `PRODUCTS` as a list, along with `TRANSACTION_ID`, `VALUE`, `CURRENCY`, and `PURCHASE_ROUTE`.

```csharp
Airflux.TrackEvent(
    category: AirfluxCategory.ORDER_COMPLETED,
    semanticAttributes: new Dictionary<string, object>
    {
        { AirfluxAttribute.TRANSACTION_ID, "TXN-20250411-0001" },
        { AirfluxAttribute.VALUE, 4.99 },
        { AirfluxAttribute.CURRENCY, "USD" },
        {
            AirfluxAttribute.PRODUCTS, new List<object>
            {
                new Dictionary<string, object>
                {
                    { AirfluxAttribute.PRODUCT_ID, "welcome_pack" },
                    { AirfluxAttribute.PRODUCT_NAME, "Welcome Pack" }
                }
            }
        },
        { AirfluxAttribute.PURCHASE_ROUTE, "shop" } // shop/popup/other
    }
);
```

***

### 5. Migrate the Inference API call (Interstitial decision)

#### 5.1 What changed

**v0.x**

* You set placement context via `setInferenceAttributes()`
* You called `InferenceShowAdInterstitial(onShowAd, onSkipAd, onFailure)`

**v1.0**

* You call `Airflux.RequestInference(...)` with `AirfluxInference.SHOW_INTERSTITIAL_AD(...)`
* You pass inference-time parameters via `AirfluxParameter.*`
* You must implement **four** callbacks:
  * `onShowAd`
  * `onSkipAd`
  * `onDefaultAdPolicy`
  * `onFailure`

> **Important**\
> v1.0 requires you to include **all required inference parameters**, and include nullable parameters whenever available.

#### 5.2 v1.0 example (recommended pattern)

```csharp
public void TryShowInterstitial()
{
    var parameters = new Dictionary<string, object>
    {
        // Required
        { AirfluxParameter.AD_TYPE, "interstitial_ad" },
        { AirfluxParameter.AD_PLACEMENT_ID, "end_of_stage_ad" },
        { AirfluxParameter.AD_PLACEMENT_TYPE, "static" },

        // Nullable (collect if available)
        { AirfluxParameter.AD_PLACEMENT_POSITION, "stage_end" },
        { AirfluxParameter.STAGE_TYPE, "primary_stage" },
        { AirfluxParameter.STAGE, 15 },
        { AirfluxParameter.STAGE_RESULT, "success" },
        { AirfluxParameter.TOTAL_FINISHED_STAGE, 42 },
        { AirfluxParameter.LEVEL, 10 }
    };

    Airflux.RequestInference(
        AirfluxInference.SHOW_INTERSTITIAL_AD(
            parameters: parameters,
            onShowAd: () =>
            {
                // AI decided to show the interstitial ad.
                ShowInterstitial();
            },
            onSkipAd: () =>
            {
                // AI decided to skip the ad.
                ContinueGameplay();
            },
            onDefaultAdPolicy: () =>
            {
                // AI requests your internal policy decision.
                ApplyMyDefaultAdPolicy();
            },
            onFailure: (error) =>
            {
                // Inference request failed (country allowlist, timeout, 4xx/5xx, etc.).
                // Apply your fallback policy. Retry is not required.
                ApplyMyDefaultAdPolicy();
            }
        )
    );
}
```

#### 5.3 Testing inference responses (QA only)

**v0.x** simulated responses via `contexts.inferenceAttributes.forceInferenceResponse`.

**v1.0** uses `AirfluxParameter.FORCE_RESPONSE` with one of:

* `"showAd"`
* `"skipAd"`
* `"defaultAdPolicy"`
* `"failure"`

Example:

```csharp
parameters[AirfluxParameter.FORCE_RESPONSE] = new Dictionary<string, object>
{
    { "action", "showAd" },
    { "parameters", new Dictionary<string, object>() }
};
```

> **Attention**\
> Force response parameters must be removed before production builds.

***

### 6. Verify your migration

#### 6.1 Check logs in Unity

* Set **Log Level = debug** during QA to see detailed Airflux logs.

#### 6.2 Verify event & inference payloads

At minimum, verify:

1. Required events are being tracked (AD\_IMPRESSION, START\_STAGE/FINISH\_STAGE, ORDER\_COMPLETED if applicable, etc.).
2. Inference requests include required parameters and trigger **exactly one** callback per request.

***

### Frequently Asked Questions

<details>

<summary>Do I still need ADID (IDFA/GAID) for Airflux?</summary>

* In Unity v0.x, Airflux required ADID collection.
* In Unity v1.0, Airflux does **not** collect ADID.

</details>

<details>

<summary>What’s the difference between onSkipAd() and onFailure()?</summary>

* `onSkipAd()` means the inference request succeeded and the model decided to skip the ad.
* `onFailure()` means the inference request failed (e.g., allowlist not matched, timeout, network/server error) and you should apply your fallback policy.

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.airflux.ai/airflux-integration-unity-v0.x/unity-v0.x-v1.0-migration-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
