Supabase
Crystal Save includes built-in support for Supabase Storage as a cloud save backend. This allows you to store save files, metadata, and screenshots in a Supabase bucket with configurable authentication and folder strategies.
1. Prepare Your Supabase Project
Create a Supabase Project
Go to supabase.com and create a new project.

Create a Storage Bucket
Navigate to Storage → New Bucket.
Example name:
game-saves.

Set Storage Policies
Go to Storage → Policies → Other policies (storage.objects).

Create policies for SELECT, INSERT, UPDATE, and DELETE according to your chosen folder strategy.



Example for a public/shared bucket:
CREATE POLICY "Anon read game-saves"
ON storage.objects
FOR SELECT TO anon
USING (bucket_id = 'game-saves');
Repeat for insert/update/delete with the appropriate clauses.

If you want per-user isolation:
Use RLS with
auth.uid()in the policy.Example for Unity Authentication:
CREATE POLICY "Player read own saves"
ON storage.objects
FOR SELECT TO authenticated
USING (
bucket_id = 'game-saves'
AND name LIKE ('users/' || auth.uid() || '/%')
);
2. Configure Crystal Save
Create and Open Save Settings
Create → Crystal Save → Settings → Create Save Settings File.
Enable Cloud Save and set:
Save Backend →
SupabaseSupabase URL → Found in your Supabase Project dashboard.
Supabase Anon Key → API key from Supabase Project settings.
Bucket Name → e.g.,
game-saves.
Choose a User Folder Strategy (
userFolderStrategy):Shared – All saves in one folder.
UnityAuthentication – Folders per Unity Auth user.
GuidPerDevice – Random GUID stored locally.
PublicPerBuild – Different public folder per build.
Custom – Fully controlled by your own resolver.
If using Custom strategy:
Assign a
CustomFolderAuthResolveror your own implementation ofIUserAuthorizationResolver.After login, call:
resolver.SetUserId(uid); resolver.SetToken(jwt); SupabaseAuthRelay.FireLoggedIn(uid);
3. Handle Authentication
Crystal Save does not force a specific login flow, but provides utilities:
Email/Password Signup:
StartCoroutine(SupabaseRestAuth.SignUpWithEmailPassword( supabaseUrl, supabaseAnonKey, email, password, (jwt, uid, needsConfirm) => { resolver.SetUserId(uid); resolver.SetToken(jwt); }, error => Debug.LogError(error)));Email/Password Signin:
StartCoroutine(SupabaseRestAuth.SignInWithPassword( supabaseUrl, supabaseAnonKey, email, password, (jwt, uid) => { resolver.SetUserId(uid); resolver.SetToken(jwt); }, error => Debug.LogError(error)));Use
SupabaseAuthRelayevents to react to login/logout.
4. Wait for Cloud Connection (Optional)
If your game must wait for a successful Supabase login before proceeding:
await SaveManager.Instance.WaitForSupabaseLoginAsync();This waits until SupabaseAuthRelay reports a login or times out.
5. Saving and Loading
Once logged in:
Call
SaveManager.SaveAsync(slotNumber)to upload the save.Call
SaveManager.LoadAsync(slotNumber)to download and load the save.Crystal Save:
Resolves the user folder based on strategy or resolver.
Uploads
.savor.jsonfile.Uploads
.meta.jsonwith slot details.Optionally uploads screenshots.
If
keepLocalMirroris enabled, stores local copies for offline play.
6. Logging Out
SaveManager.Instance.LogoutFromSupabase();Clears stored credentials from the resolver.
Resets cloud save state.
Mermaid Flow Diagram
Last updated