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

# Initialize the SDK

> How to integrate the Almedia SDK — synced from the source repository.

With a `LinkButton` prefab in the scene, calling `Initialize` yourself is optional (unless **Auto-Initialize From Prefabs** in **Almedia → Settings** is off). If nothing has called `Initialize` by the end of the button's first frame, the button calls it with the values from **Almedia → Settings**. With the integration keys set there, dropping a button onto a Canvas is a complete integration.

Calling `Initialize` yourself is still useful, for example to pass runtime values such as `AccountId` or advertising identifiers like `Idfa` and `Gaid`, or to control the timing, e.g. waiting for the player's consent.

For the default behavior, do nothing: drop the prefab and set the keys. To opt out, call `Initialize` yourself and optionally untick **Auto-Initialize From Prefabs**. Your explicit configuration always wins. A call in the button's first frame or earlier runs first and the prefab stands down. A later call with a different configuration re-initializes the session and your configuration applies.

Initialize once per app launch, as early as advertising identifiers and a player ID become available. Calling `Initialize` again is safe: a call with the same effective configuration is a no-op that preserves the status, while a call with a different configuration re-initializes the session. A minimal bootstrap:

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
using UnityEngine;
using AlmediaSDK;

public class AlmediaBootstrap : MonoBehaviour
{
    void Awake()
    {
        Almedia.OnStatusChanged         += HandleStatusChanged;
        Almedia.OnLinkCompleted         += HandleLinkCompleted;
        Almedia.OnNotificationsReceived += HandleNotifications;
        Almedia.OnErrorOccurred         += HandleError;

        Almedia.Initialize(new AlmediaConfig
        {
            // IDs improve attribution and cover devices where automatic collection fails.
            // IDs that don't apply to the current platform are ignored.
            Idfa = "YOUR_IDFA",
            Gaid = "YOUR_GAID",
        });
    }

    void HandleStatusChanged(AlmediaStatus status) { /* ... */ }
    void HandleLinkCompleted(string linkedAt) { /* ... */ }
    void HandleNotifications(System.Collections.Generic.List<AlmediaNotification> items) { /* ... */ }
    void HandleError(AlmediaError error) { /* ... */ }
}
```

The advertising IDs and `AccountId` are runtime-only fields with no settings fallback. The native SDK collects device identifiers on its own where the platform allows. IDs you pass cover the devices where that collection comes up empty, and improve attribution everywhere.

Rules:

* **Call `Initialize` on the Unity main thread**, like every SDK method. Callbacks from other SDKs, such as remote config or login, can run on a background thread. Move to the main thread before you call `Initialize` from one. See [Threading](https://docs.almedia.dev/technical/integration-guide/threading.md).
* **Subscribe to `OnStatusChanged` before calling `Initialize`** if you want to observe every transition (including the first one). Subscriptions added later still receive subsequent transitions; the first one is the only one you can miss.
* **For late-joining components, read `Almedia.Status` directly.** UI that spawns after init has already completed can recover the current state without waiting for the next change. The pattern is:

  ```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
  UpdateUi(Almedia.Status);
  Almedia.OnStatusChanged += UpdateUi;
  ```
* **Do not pass keys in code when they are already set in `AlmediaLinkSettings`.** The keys on `AlmediaConfig` are runtime overrides. A non-empty config value wins; an empty value falls back to the settings asset. The platform-correct key is selected automatically (`UNITY_IOS` → iOS key, `UNITY_ANDROID` → Android key).
* **Pass an `AccountId` when available.** This is the host's internal player ID. It is opaque to Almedia; keep its format stable so the same player is recognized across sessions.
* **Pass advertising identifiers when available.** All nine improve attribution: `AccountId`, `Idfa` (iOS), `Idfv` (iOS), `Gaid` (Android), `Asid` (Android App Set ID), `Oaid` (Huawei/CN), `AdjustDeviceId`, `AppsFlyerId`, `TenjinAnalyticsInstallationId`. On Android the native SDK collects identifiers on its own where the platform allows. Identifiers that don't apply to the current platform are ignored by the native SDK, so they can be set unconditionally. Pass empty strings or omit the rest when unavailable. `Idfv` is optional: when omitted the iOS SDK collects it automatically; supply a value only to override the device-issued one. `AdjustDeviceId`, `AppsFlyerId` and `TenjinAnalyticsInstallationId` are collected automatically too: when the Adjust, AppsFlyer or Tenjin SDK is in the app and the backend has enabled it for your integration, the native SDK reads the ID the vendor SDK has stored on the device, so passing them is only needed to override that value.

`TrafficSource` is where the user was originally acquired, sent as `sub3` on the linking magic link only. Pass your MMP's media source verbatim, e.g. `applovin_int` or `googleadwords_int`. It follows the same rules as meta below.

`Meta1`-`Meta4` are four optional passthrough values appended to the linking magic link and to nothing else. The SDK never interprets them; they exist for publishers who need their own payload returned in S2S reporting, and can be left unset otherwise. Each is capped at 250 UTF-8 bytes, a longer value is dropped with a warning, and changing one re-initializes the session - set them once, at startup. The API reference covers the detail.

## Config-vs-settings precedence

When `Initialize` runs, the SDK merges any supplied `config` with `AlmediaLinkSettings`:

| Field | Priority order |
| - | - |
| Integration key | `config.IosIntegrationKey` / `config.AndroidIntegrationKey` → settings asset |
| `NotificationsPollingIntervalSec` | backend (if set) → config (if non-null) → settings → 30 |
| `DisabledFeatures` | settings ∪ config - the asset is the floor, code adds and never removes |
| `Gaid` / `Asid` / `Oaid` / `Idfa` / `Idfv` / `AdjustDeviceId` / `AppsFlyerId` / `TenjinAnalyticsInstallationId` / `AccountId` / `TrafficSource` / `Meta1`-`Meta4` | config only (no settings fallback) |

If neither the config nor the settings asset supplies an integration key, `Initialize` fires `OnErrorOccurred` with `AlmediaErrorCode.InvalidConfiguration` and does not contact the backend.

***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.