---
name: rudder-unity-sdk
description: Use when working with the Rudder Unity SDK rudder.sdk in a Unity project — install, bootstrap, auth, remote config, storage, stores, inventory, leaderboards, quests, battle pass, scenarios.
---

# Rudder Unity SDK (`rudder.sdk`)

UPM package `rudder.sdk` (v0.4.0): LiveOps SDK for Unity. It wraps
`Rudder.Core.dll` (namespace `RudderSdk.Core`, the .NET SDK) with Unity
adapters in `RudderSdk.Unity`. Public API surface:

- `RudderSdk.Unity` — `Rudder` (MonoBehaviour bootstrap), `RudderConfiguration`,
  `RudderState`, platform adapters.
- `RudderSdk.Core` — `RudderClient` and feature services (`Auth`, `Player`,
  `RemoteConfig`, `Storage`, `ProjectStorage`, `Stores`, `Inventory`,
  `Leaderboards`, `Quests`, `BattlePass`, `Scenario`, `Effects`).
- `RudderSdk.Core.Models.*` — DTOs (`PlayerProfile`, `Wallet`, `Offer`,
  `Store`, `StorageItem`, `RankEntry`, `Quest`, `Reward`, ...).

Full integration rules live in `Packages/rudder.sdk/AGENTS.md`; copy-paste
sample scenes live in `Packages/rudder.sdk/Samples~/`. Verify signatures
against those, never from memory.

## Install

Unity 6000.0+. Add the scoped registry and both dependencies to
`Packages/manifest.json` (`com.unity.nuget.newtonsoft-json` is required —
the package does not bundle Newtonsoft.Json):

```json
{
  "scopedRegistries": [
    {
      "name": "Rudder",
      "url": "https://hub.rudder.build/api/packages/rudder/npm/",
      "scopes": ["rudder"]
    }
  ],
  "dependencies": {
    "rudder.sdk": "0.4.0",
    "com.unity.nuget.newtonsoft-json": "3.2.2"
  }
}
```

## Bootstrap

1. Create the configuration asset: `Assets > Create > Rudder > Configuration`.
2. Set `ProjectKey` (required). Defaults: `BaseUrl` `https://api.rudder.build`,
   `TimeoutSeconds` 10.
3. Add the `Rudder` component to a startup scene object and assign the asset.
   `Rudder` is `[DefaultExecutionOrder(-1500), DisallowMultipleComponent]`,
   uses `DontDestroyOnLoad`, and pumps `client.Update(Time.deltaTime)` every
   frame — never call `client.Update` yourself.
4. Initialize and sign in:

```csharp
using RudderSdk.Unity;

var client = Rudder.Initialize();                                  // synchronous, idempotent
await client.Auth.LoginWithDeviceAsync("global", "en", nickname: "Player");
```

`Rudder.Initialize()` throws if the component or configuration is missing.
`Rudder.State` (`NotInitialized`/`Initializing`/`Ready`/`Failed`),
`Rudder.LastError`, `Rudder.Client`, `Rudder.Ready` (Task) and
`Rudder.Initialized` (event) expose lifecycle. Details:
[reference/bootstrap.md](reference/bootstrap.md).

## Platform adapters

`RudderUnityClientFactory.Create(RudderUnityClientOptions)` wires Core
abstractions to Unity implementations; `Rudder.Initialize()` does this for
you with `PlayerPrefsUnityKeyValueStore` + `UnityDebugLoggerSink`:

| Core abstraction | Unity adapter | Notes |
| --- | --- | --- |
| `IRudderTransport` | `UnityTransportAdapter` over `UnityWebRequestExecutor` | `UnityWebRequest`, timeout from config |
| `ITokenStore` | `UnityTokenStoreAdapter` | tokens in PlayerPrefs |
| `IDeviceIdProvider` | `UnityDeviceIdProvider` | GUID in PlayerPrefs (`rudder_device_id`) — not `SystemInfo.deviceUniqueIdentifier` |
| `IClock` | `UnityClock` | `DateTimeOffset.UtcNow` |
| `IRudderLogger` | `UnityLoggerAdapter` → `IUnityLoggerSink` | default `UnityDebugLoggerSink` → `Debug.Log*` |

## Capabilities

All calls hang off `client` / `Rudder.Client`. Match the task to one row,
then read the reference file for exact signatures.

| Task | API | Reference |
| --- | --- | --- |
| Init, sign in, profile, wallets, errors | `Rudder.Initialize`, `client.Auth.LoginWithDeviceAsync`, `Auth.*`, `Player.GetProfileAsync` | [reference/bootstrap.md](reference/bootstrap.md), [reference/authentication.md](reference/authentication.md) |
| Remote tunables | `RemoteConfig.LoadAsync`, `Get<T>(key, fallback)`, `GetAsync` | [reference/remote-config.md](reference/remote-config.md) |
| Player cloud save / project storage | `Storage.GetAsync`/`SaveAsync`/`DeleteAsync`, `ProjectStorage.*` | [reference/storage.md](reference/storage.md) |
| Shop + inventory | `Stores.ListAsync`/`GetAsync`/`PurchaseAsync`, `Inventory.GetAsync` | [reference/stores-inventory.md](reference/stores-inventory.md) |
| High scores | `Leaderboards.FindBySlug(slug)` → `SubmitAsync`/`ListAsync` | [reference/leaderboards.md](reference/leaderboards.md) |
| LiveOps scenarios | `Scenario.TriggerAsync`, `Effects.OnNotification`/`OnStoreOffer`/... | [reference/scenarios.md](reference/scenarios.md) |
| Global quests | `Quests.ListAsync`/`ClaimAsync`/`ReportProgressAsync` | [reference/quests.md](reference/quests.md) |
| Battle pass | `BattlePass.*` with scenario/node ids, `BattlePassEffect` | [reference/battlepass.md](reference/battlepass.md) |

## Hard rules

- Call the SDK from a `MonoBehaviour` or the game's service object; no second
  singleton next to `Rudder`, no wrapper layers, no consumer-local interfaces
  over `RudderClient`.
- Use SDK model types directly; do not re-wrap `Offer`/`PlayerProfile`/
  `RankEntry` in project DTOs unless asked.
- No `ConfigureAwait(false)` in game code — continuations must return to the
  Unity synchronization context.
- Catch `RudderApiException` subclasses and surface `exception.Message`;
  do not swallow errors. A 401 is retried once after a token refresh by the
  client itself.
- Backend entities must exist: store slug, leaderboard slug, remote-config
  key, scenario event. Missing data is a 404, not an SDK bug.
- Every feature call requires a matching dashboard entity; the API base is
  `https://api.rudder.build`, dashboard `https://app.rudder.build/`.
