Losing player progress is one of the fastest ways to get a 1-star review on the App Store or Google Play. If you’re an indie developer shipping a mobile game in 2026, implementing cloud saves for your mobile game is no longer optional, it’s expected. Players switch devices, reinstall apps, and demand that their progress follows them everywhere.
In this practical tutorial, we’ll walk through how to build a robust cross-device cloud save system using Firebase Firestore in Unity, targeting both iOS and Android. We’ll also tackle the trickiest part: resolving conflicts between local and cloud data.
Why Firebase Firestore for Cloud Saves in Mobile Games?
You have plenty of options for cloud saves: Google Play Games Services, Apple’s Game Center, Epic Online Services, or building your own backend. Here’s why Firebase Firestore is a strong pick for indie devs:
- Cross-platform by default: One codebase works on iOS and Android without duplicating logic.
- Generous free tier: Spark plan covers most indie games until they scale.
- Real-time sync: Firestore pushes updates when data changes, useful for multi-device players.
- Simple authentication: Firebase Auth handles anonymous, Google, and Apple sign-in out of the box.
- Offline support: Built-in local caching for offline play.
Firebase vs Other Cloud Save Options
| Solution | Cross-platform | Conflict Handling | Cost |
|---|---|---|---|
| Firebase Firestore | Yes | Custom (flexible) | Free tier + pay as you go |
| Google Play Games Services | Android only | Built-in | Free |
| Apple Game Center | iOS only | Built-in | Free |
| Epic Online Services | Yes | Built-in | Free |

Step 1: Set Up Firebase in Your Unity Project
- Go to the Firebase Console and create a new project.
- Add both an iOS app (with your bundle ID) and an Android app (with your package name).
- Download the
GoogleService-Info.plist(iOS) andgoogle-services.json(Android) and drop them intoAssets/. - Download the Firebase Unity SDK and import these packages:
- FirebaseAuth.unitypackage
- FirebaseFirestore.unitypackage
- In Player Settings, make sure iOS is set to a minimum of iOS 13 and Android minimum API level 24.
Step 2: Authenticate the Player
Before saving anything to the cloud, we need a stable user ID. Anonymous auth is the fastest way to onboard players without forcing a login screen, and you can upgrade to Google/Apple sign-in later.
using Firebase.Auth;
using System.Threading.Tasks;
using UnityEngine;
public class AuthManager : MonoBehaviour
{
private FirebaseAuth auth;
public string UserId { get; private set; }
async void Start()
{
auth = FirebaseAuth.DefaultInstance;
await SignInAnonymously();
}
private async Task SignInAnonymously()
{
try
{
var result = await auth.SignInAnonymouslyAsync();
UserId = result.User.UserId;
Debug.Log($"Signed in as: {UserId}");
}
catch (System.Exception e)
{
Debug.LogError($"Auth failed: {e.Message}");
}
}
}
Step 3: Design Your Save Data Model
Keep your save schema flat and versioned. This makes migrations painless when you add new features later.
[System.Serializable]
public class PlayerSave
{
public int schemaVersion = 1;
public long lastUpdatedUnix;
public string deviceId;
public int level;
public int coins;
public int gems;
public string[] unlockedItems;
}
The two critical fields for conflict resolution are lastUpdatedUnix and deviceId. We’ll use them shortly.

Step 4: Write to Firestore
using Firebase.Firestore;
using Firebase.Extensions;
using UnityEngine;
public class CloudSaveManager : MonoBehaviour
{
private FirebaseFirestore db;
void Start()
{
db = FirebaseFirestore.DefaultInstance;
}
public void SaveToCloud(string userId, PlayerSave save)
{
save.lastUpdatedUnix = System.DateTimeOffset.UtcNow.ToUnixTimeSeconds();
save.deviceId = SystemInfo.deviceUniqueIdentifier;
DocumentReference docRef = db.Collection("saves").Document(userId);
docRef.SetAsync(save).ContinueWithOnMainThread(task =>
{
if (task.IsCompletedSuccessfully)
Debug.Log("Cloud save successful.");
else
Debug.LogError("Cloud save failed: " + task.Exception);
});
}
}
Step 5: Load from Firestore
public void LoadFromCloud(string userId, System.Action<PlayerSave> onLoaded)
{
DocumentReference docRef = db.Collection("saves").Document(userId);
docRef.GetSnapshotAsync().ContinueWithOnMainThread(task =>
{
if (task.IsCompletedSuccessfully && task.Result.Exists)
{
PlayerSave cloudSave = task.Result.ConvertTo<PlayerSave>();
onLoaded?.Invoke(cloudSave);
}
else
{
onLoaded?.Invoke(null);
}
});
}
Step 6: Handling Conflicts Between Local and Cloud Saves
This is where most indie developers get burned. A player opens the game on device B, plays for two hours, then opens device A which still has an older local save. Which one wins?
The 3-Rule Conflict Resolution Strategy
- Same device ID: Trust the newer timestamp automatically.
- Different device, cloud is newer: Prompt the player, defaulting to cloud.
- Different device, local is newer: Prompt the player, defaulting to local, but ALWAYS show what they’d lose.
public enum ConflictResolution { UseLocal, UseCloud, AskUser }
public ConflictResolution ResolveConflict(PlayerSave local, PlayerSave cloud)
{
if (local == null) return ConflictResolution.UseCloud;
if (cloud == null) return ConflictResolution.UseLocal;
bool sameDevice = local.deviceId == cloud.deviceId;
bool cloudNewer = cloud.lastUpdatedUnix > local.lastUpdatedUnix;
if (sameDevice)
return cloudNewer ? ConflictResolution.UseCloud : ConflictResolution.UseLocal;
long diff = System.Math.Abs(cloud.lastUpdatedUnix - local.lastUpdatedUnix);
if (diff < 60) return ConflictResolution.UseCloud;
return ConflictResolution.AskUser;
}
When you prompt the user, show a clear comparison:
| Field | This Device | Cloud |
|---|---|---|
| Level | 12 | 17 |
| Coins | 450 | 1,220 |
| Last played | 3 days ago | 2 hours ago |

Step 7: Platform-Specific Considerations
Android
- Enable SHA-1 fingerprint for your keystore in the Firebase Console (required for Google Sign-in later).
- Add
<uses-permission android:name="android.permission.INTERNET"/>if not already in your manifest. - Test on physical devices, emulators sometimes have issues with Google Play Services.
iOS
- In Xcode, ensure the
GoogleService-Info.plistis added to the target. - Set Bitcode to No, Firebase Unity SDK doesn’t support it.
- If shipping to the EU, remember to declare Firebase in your App Privacy manifest (required since iOS 17).
Step 8: Firestore Security Rules
Never leave Firestore in test mode when you ship. Use these rules to ensure players can only read and write their own save:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /saves/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
Best Practices for Cloud Saves in Production
- Save on lifecycle events: Trigger a cloud sync in
OnApplicationPauseandOnApplicationQuit. - Debounce writes: Don’t push every coin pickup, batch changes every 30 to 60 seconds.
- Keep local saves as a fallback: Cloud can fail, PlayerPrefs or a JSON file should always exist.
- Version your schema: When you add fields, write migration code before deserializing old saves.
- Log conflicts: Send an analytics event when a user picks local over cloud, this helps you spot bugs.
FAQ
Can you use cloud storage for mobile games without a backend team?
Yes. Firebase Firestore is designed for solo devs and small teams. You don’t need to write server code, the SDK handles authentication, storage, and sync directly from Unity.
Will players lose progress if they get a new phone?
Not if you implement cloud saves correctly. As long as the player signs in with the same account (Google, Apple, or a linked anonymous account), Firestore will restore their save on the new device.
How much does Firebase Firestore cost for a mobile game?
The Spark (free) plan includes 50,000 reads, 20,000 writes, and 1 GB of storage per day. For most indie mobile games with under 10,000 daily active users, this is enough. Beyond that, Blaze pay-as-you-go is typically cents per day per thousand active users.
Should I use Firebase or Google Play Games Services for Android cloud saves?
If your game is Android-only, Google Play Games Services is free and integrates well. If you’re shipping on both iOS and Android, Firebase gives you one unified system, which is far easier to maintain.
How do I handle offline players?
Firestore has built-in offline persistence enabled by default in the Unity SDK. Writes made offline are queued and pushed automatically when the device reconnects. Always keep a local save file as a hard backup.
Wrapping Up
Implementing cloud saves for a mobile game with Firebase Firestore takes an afternoon to set up and pays off for the entire lifetime of your game. Players expect their progress to follow them, and giving them that experience translates directly into better reviews, higher retention, and fewer support tickets.
At Falanxia, we help studios ship polished mobile games with production-grade backends, analytics, and live-ops tooling. If you need help architecting your cloud save system or scaling it beyond the Firebase free tier, get in touch.
