# Nakama Cloud Save Sample Project

**URL:** https://heroiclabs.com/docs/sample-projects/unity/nakama-cloud-save/
**Summary:** Cloud save sample project for Unity games
**Keywords:** nakama cloud save, unity, facebook authentication, social providers, account linking, authentication, cloud storage, facebook unity sdk, social login, meta developer account
**Categories:** unity, sample-projects, nakama-cloud-save

---


Although Facebook is used in this sample project, other [social providers](../../../nakama/concepts/authentication/#social-providers) are supported as well e.g., Google, Steam, Apple, and so on. You will need your own developer account in order to connect to these providers.

### Setting up with Facebook

In order to authenticate or link an account to Facebook, you'll need your own Meta developer account and credentials. This project comes pre-loaded with the Facebook Unity SDK so you don't need to download and install the package yourself.

1. Register as a [Meta developer](https://developers.facebook.com/docs/development/register) if you haven't done so already.
2. Follow the steps in the Facebook Unity SDK guide to retrieve your **Facebook App ID** and **Client token**.
3. In the Unity editor, select **Facebook > Edit Settings** and add your credentials to their respective fields.

You'll need to **Build and run** the project in order to authenticate or link an account with Facebook, as requests to third-party services don't work while running the project inside the Unity Editor.

## See the Cloud Save feature in action

1. Click **Sign in as Guest**. The system creates a new player account using [device authentication](../../../nakama/client-libraries/unity/index.html#device-authentication).
2. Under **Data Simulator**, enter a number in **Points** and select **Submit**.
3. Select **Link Facebook** to link this account to Facebook. Follow the prompts.
4. Close the window and **Build and run** the project again.
5. This time, select **Sign in with Facebook**.

The dialog displays the same points value you entered earlier. This is because Nakama recognizes your account and loads your saved data.

## Code overview

#### Main controller (`NakamaCloudSaveController.cs`)

Handles all core operations including authentication and cloud storage.

**Authentication**

Supports both device authentication and Facebook authentication:

```csharp
// Device authentication using device ID
private async Task AuthenticateWithDevice()
{
    var deviceId = PlayerPrefs.GetString("deviceId", SystemInfo.deviceUniqueIdentifier);
    session = await client.AuthenticateDeviceAsync(deviceId);
}

// Facebook authentication
private async void AuthenticateWithFacebook()
{
    // Authenticate with Facebook if session does not exist, otherwise link to Facebook
    if (session != null)
    {
        await client.LinkFacebookAsync(session, AccessToken.CurrentAccessToken.TokenString, false);
    }
    else
    {
        session = await client.AuthenticateFacebookAsync(AccessToken.CurrentAccessToken.TokenString, null, true, false);
    }
}
```

**Cloud storage**

```csharp
// Save data to Nakama cloud storage
private async Task HandleSubmitData(int points)
{
    var pointsData = new PointsData
    {
        points = points,
        timestamp = System.DateTime.UtcNow.ToString("o")
    };

    var writeObject = new WriteStorageObject
    {
        Collection = "points",
        Key = "latest_points",
        Value = pointsData.ToJson(),
        PermissionRead = 1,  // Only server and owner can read
        PermissionWrite = 1  // Only server and owner can write
    };

    await client.WriteStorageObjectsAsync(session, new IApiWriteStorageObject[] { writeObject });
}

// Load data from cloud storage
private async Task LoadLatestData()
{
    var readObjectId = new StorageObjectId
    {
        Collection = "points",
        Key = "latest_points",
        UserId = session.UserId
    };

    var result = await client.ReadStorageObjectsAsync(session, new IApiReadStorageObjectId[] { readObjectId });

    // Process retrieved data and update UI
    if (result.Objects.Any())
    {
        var pointsData = result.Objects.First().Value.FromJson<PointsData>();
        pointsLabel.text = $"Points: {pointsData.points}";
    }
}
```
