JavaScript Templates

JavaScript templates for one-save, slots, account restore, and connect-later.

Use @persistlyapp/sdk through PersistlyGameSaves first. Start with saveData for one current save, move to saveSlot for named slots, attach a known account session from trusted backends, or connect anonymous progress to Firebase, Supabase, or Auth0 later.

One SaveMultiple SlotsAccount + SlotsConnect Later

One Save

JavaScript one-save starter

When to use this: Use this for idle, casual, and prototype games that keep one current save.

JavaScript starter

JavaScript one-save starter

Copy this into your game-facing save service, then adapt the data type and safe sync moments to your game.

TYPESCRIPT
import { PersistlyGameSaveStatus, PersistlyGameSaves } from "@persistlyapp/sdk";

await PersistlyGameSaves.configure({
  runtimeKey: "ps_test_replace_me",
});

export async function saveGame(gameState: Record<string, unknown>) {
  await PersistlyGameSaves.shared.saveData(gameState);
}

export async function loadGame() {
  const loaded = await PersistlyGameSaves.shared.loadData();
  return loaded.status === PersistlyGameSaveStatus.LocalFound ? loaded.data : null;
}

export async function syncAfterCheckpoint() {
  return PersistlyGameSaves.shared.forceSyncData();
}

Persist your normal game state through saveData.

Read local state first with loadData so the game can boot offline.

Call forceSyncData from pause, checkpoint, manual save, or level-complete moments.

Multiple Slots

JavaScript multiple-slot starter

When to use this: Use this when the game has manual saves, campaigns, save files, or character selection.

JavaScript starter

JavaScript multiple-slot starter

Copy this into your game-facing save service, then adapt the data type and safe sync moments to your game.

TYPESCRIPT
import { PersistlyGameSaveStatus, PersistlyGameSaves } from "@persistlyapp/sdk";

await PersistlyGameSaves.configure({
  runtimeKey: "ps_test_replace_me",
});

export async function saveCampaign(slotId: string, gameState: Record<string, unknown>) {
  await PersistlyGameSaves.shared.saveSlot(slotId, gameState, {
    slotInfo: { label: slotId },
  });
}

export async function loadCampaign(slotId: string) {
  const loaded = await PersistlyGameSaves.shared.loadSlot(slotId);
  return loaded.status === PersistlyGameSaveStatus.LocalFound ? loaded.data : null;
}

export async function syncCampaign(slotId: string) {
  return PersistlyGameSaves.shared.forceSync(slotId);
}

Choose stable developer slot ids such as autosave, slot-1, slot-2, or warrior.

Keep menu labels and timestamps in slotInfo so save selection UI can stay fast.

Sync the active slot from safe lifecycle or manual-save points.

Account + Slots

JavaScript account + slots starter

When to use this: Use this when your own sign-in flow stores and restores the Persistly account session.

JavaScript starter

JavaScript account + slots starter

Copy this into your game-facing save service, then adapt the data type and safe sync moments to your game.

TYPESCRIPT
import { PersistlyGameSaves } from "@persistlyapp/sdk";

await PersistlyGameSaves.configure({
  runtimeKey: "ps_test_replace_me",
});

export async function exportSessionForYourBackend() {
  await PersistlyGameSaves.shared.ensureAccount();
  return PersistlyGameSaves.shared.getAccountSession({ includeToken: true });
}

export async function restoreKnownAccount(accountId: string, accountSessionToken: string) {
  await PersistlyGameSaves.shared.attachAccount({
    accountId,
    accountSessionToken,
  });
}

export async function saveSignedInSlot(slotId: string, gameState: Record<string, unknown>) {
  await PersistlyGameSaves.shared.saveSlot(slotId, gameState, {
    slotInfo: { label: slotId },
  });
  return PersistlyGameSaves.shared.forceSync(slotId);
}

Store accountId and accountSessionToken only in your trusted account system.

Restore with attachAccount before loading or refreshing signed-in slots.

Keep normal gameplay writes on saveSlot so account restore stays facade-first.

Connect Later

JavaScript anonymous-first connect-later starter

When to use this: Use this when players can start immediately, save progress, and connect Firebase, Supabase, or Auth0 later.

JavaScript starter

JavaScript anonymous-first connect-later starter

Copy this into your game-facing save service, then adapt the data type and safe sync moments to your game.

TYPESCRIPT
import { PersistlyGameSaves } from "@persistlyapp/sdk";

await PersistlyGameSaves.configure({
  runtimeKey: "ps_test_replace_me",
  accountMode: "anonymousFirst",
});

export async function saveBeforeSignIn(gameState: Record<string, unknown>) {
  await PersistlyGameSaves.shared.saveData(gameState);
  return PersistlyGameSaves.shared.forceSyncData();
}

export async function connectFirebaseAccount(firebaseIdToken: string) {
  try {
    return await PersistlyGameSaves.shared.connectWithFirebaseToken(firebaseIdToken);
  } catch (error) {
    if (error && typeof error === "object" && "code" in error && error.code === "account_auth_conflict") {
      return { status: "account_auth_conflict", currentAccountPreserved: true };
    }

    throw error;
  }
}

Use anonymousFirst so save/load works before player sign-in.

Get the provider token from Firebase, Supabase, or Auth0; Persistly does not provide login UI in this phase.

On account_auth_conflict, keep local progress. Let the player retry with a different provider account or explicitly discard local Persistly state before using the existing provider-linked account.