> For the complete documentation index, see [llms.txt](https://lionstudios.gitbook.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lionstudios.gitbook.io/readme/features/remote-storage.md).

# Remote Storage

### Installation

* Complete the steps in [Getting Started](/readme/getting-started.md) if LionSDK is not installed.
* If LionSDK is already installed,
  * Install the package `Lion - Remote Storage` .

<figure><img src="/files/8misbjnWfNvPuDyHX5Or" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Make sure the “Hide Package” button is disabled to see the relevant package folders.\
![](/files/80E1ceLLOAagaJ4ZJma7)
{% endhint %}

### Quick Start

1. Setup [Firebase](/readme/features/remote-configs/firebase.md).
2. Setup [Firestore](/readme/features/remote-storage/firestore.md).
   1. If integrated, users will be able to retrieve game data even after reinstall.
3. Setup [Facebook Authentication](/readme/features/remote-storage/firestore/facebook-auth.md) (Optional, but recommended, if you want Facebook login data sync)
   1. If integrated, users will be able to retrieve game data from their other devices after a Facebook login.

### Implementation

#### Reading & Writing Data

All reads and writes are instant and local:

```csharp
RemoteStorage.SetInt("coins", 100);
int coins = RemoteStorage.GetInt("coins", 0);
RemoteStorage.SetValue("profile", playerProfile);
```

#### Saving to the Cloud

Cloud saving is manual — call the awaitable `Save()` Whenever you want to push data to the cloud:

```csharp
bool synced = await RemoteStorage.Save();
if (!synced)
{
    // Cloud unreachable
}
```

* Returns `true` once the data has reached the cloud.
* Returns `false` If the cloud cannot be reached, local data is safe.
* If authentication or the first sync failed (for example, the game started offline), the next `Save()` sync recovers by itself — it authenticates, pulls and merges the cloud save, then pushes. `OnRemoteDataUpdated` fires if the cloud save wins that merge.

{% hint style="info" %}
Call `Save()` at meaningful moments — after level completion, after a purchase, or on app pause. Data also syncs once automatically during module initialization (pull → merge → push).
{% endhint %}

#### Using the `OnRemoteDataUpdated` Event

When data is synced from the cloud, a **merge conflict** may occur between local and remote data. If the remote data wins (because it has a more recent purchase, higher XP, or newer save time), the local data is replaced.

When this happens, `RemoteStorage.OnRemoteDataUpdated` fires so your game can **reload its in-memory state**. This is also the right moment to tell the player their progress was restored — for example, show a popup saying the save was loaded from the cloud.

```csharp
RemoteStorage.OnRemoteDataUpdated += () =>
{
    // Cloud data replaced local data — reload your in-memory state
    coins = RemoteStorage.GetInt("coins", 0);
    volume = RemoteStorage.GetFloat("volume", 1f);
    playerProfile = RemoteStorage.GetValue<PlayerProfile>("profile", new PlayerProfile());
};
```

{% hint style="warning" %}
If you cache storage values in memory (e.g. at game start), those cached values will be **stale** after a cloud merge. Always listen to `OnRemoteDataUpdated` and re-read your data to keep your game state in sync.
{% endhint %}

<details>

<summary>Advanced</summary>

### Initialization Flow

1. `Initialize()` loads data from **PlayerPrefs immediately** and returns without waiting for the cloud.
2. **Background sync** starts: Firebase Email/Password auth → pull remote data → merge → push.
3. Remote Storage **does NOT block** LionSDK initialization.

{% hint style="info" %}
**`IsDataReady` Behaviour differs by session type:**

* **Returning user** (local data exists): `IsDataReady = true` Local data is playable immediately.
* **First session** (no local data): `IsDataReady = true` only after the background cloud sync completes (or fails). Show a loading indicator until ready.
  {% endhint %}

***

### Architecture Overview

Remote Storage uses a **local‑first architecture**. All reads and writes are instantly saved to local storage (PlayerPrefs). Cloud synchronization with Firestore happens **in the background**, so it never blocks your game.

```
Game Code → RemoteStorage API → LocalStorage (PlayerPrefs) → instant reads/writes
                                         ↕
                               CloudSyncManager (background)
                                         ↕
                                  Firestore (cloud)
```

</details>

<details>

<summary>API</summary>

### RemoteStorage Static API

| Member                                         | Type                      | Description                                                                                                                                   |
| ---------------------------------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `IsInitialized`                                | `bool`                    | `true` once the module has completed initialization (local data loaded).                                                                      |
| `OnInitialized`                                | `event Action`            | Fires when initialization completes.                                                                                                          |
| `CurrentSyncState`                             | `SyncState`               | Current cloud sync state.                                                                                                                     |
| `OnSyncStateChanged`                           | `event Action<SyncState>` | Fires when sync state changes.                                                                                                                |
| `CurrentMergeConflictData`                     | `MergeConflictData`       | The current merge conflict data from the active storage, or `null`.                                                                           |
| <p></p><p><code>OnRemoteDataUpdated</code></p> | `event Action`            | Fires when cloud data replaces local data after a merge — reload cached values and optionally show a save-restored popup.                     |
| `IsDataReady`                                  | `bool`                    | `true` when save data is ready to read. On a first session it becomes `true` only after the initial cloud sync attempt.                       |
| `Save()`                                       | `Task<bool>`              | Saves locally and pushes data to the cloud. Returns `false` if the cloud could not be reached — local data is safe.                           |
| `Save(MergeConflictData)`                      | `Task<bool>`              | Same as `Save()`, but updates the merge conflict data first. Call it after progression or purchase updates.                                   |
| `DeleteAll()`                                  | `void`                    | Clears local data, deletes the cloud save, and removes the account — the next session starts fresh. Used by the LionSDK delete-progress flow. |

### SyncState API

Use the `SyncState` API to monitor the current status of the cloud synchronization.

#### SyncState Enum

| State            | Description                                           |
| ---------------- | ----------------------------------------------------- |
| `LocalOnly`      | Cloud sync has not started yet (initial state).       |
| `Authenticating` | Firebase email auth is in progress.                   |
| `Syncing`        | Pulling or pushing data to Firestore.                 |
| `Synced`         | Cloud and local data are in sync.                     |
| `Failed`         | Auth or sync failed. Local data is safe and playable. |

#### Checking Current State

```csharp
if (RemoteStorage.CurrentSyncState == SyncState.Synced)
{
    Debug.Log("Cloud data is in sync!");
}
```

#### Subscribing to State Changes

```csharp
RemoteStorage.OnSyncStateChanged += (state) =>
{
    Debug.Log($"Sync state changed: {state}");
    
    if (state == SyncState.Failed)
    {
        // Show offline indicator to the player
    }
};
```

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://lionstudios.gitbook.io/readme/features/remote-storage.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
