> For the complete documentation index, see [llms.txt](https://wiki.playgama.com/playgama/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wiki.playgama.com/playgama/guides/game-development/saving-progress.md).

# Saving progress

What to save, how to structure storage keys, when to write, and how to version saves.

Progress that is lost after a reload, or saved past the SDK, is the most frequent reason a game is sent back. The rules are in section 3.2 of the [User Experience Requirements](/playgama/game-requirements/user-experience-requirements.md), and the API is the [Storage module](/playgama/bridge-sdk/api/storage.md). This guide is about structuring saves so they stay correct.

## Decide what to save

Save everything the player would be upset to lose, and nothing that can be recomputed:

* progression: the current and unlocked levels, the best score, stars per level;
* the economy: coins, gems, inventory, upgrades;
* settings: the player's mute choice, language choice if the game offers one, control options;
* one-time flags: tutorial completed, onboarding steps seen.

Do not save positions of every object, caches or anything derived from the data above.

## Keep saves in a few keys

* Group the data into a small, fixed set of keys — for example `progress`, `economy` and `settings` — and store each as one JSON value.
* Read all of them in one [`storage.get([...])`](/playgama/bridge-sdk/api/storage.md#load-data) call at startup, after Bridge initialization and before the first gameplay frame. Show the game only when the state is restored.
* Write with one [`storage.set([...], [...])`](/playgama/bridge-sdk/api/storage.md#save-data) call that includes every key that changed.
* Never use `localStorage`, `sessionStorage`, IndexedDB, cookies or an engine's own save system (such as `PlayerPrefs` in Unity) — the Bridge picks the right storage for each platform, cloud saves included (item 3.2.1).

## Write at the right moments

* Save when something meaningful changes: a level completed or failed, a purchase, a reward, a settings change.
* Never save every frame, every second or on every tap — platforms limit how often data can be written, and moderation flags abnormal numbers of calls.
* If the game changes the state very often, such as an idle game counting coins, keep it in memory and save it on a timer of tens of seconds and at the next meaningful moment.
* Save before anything that can end the session: before showing an ad, before a purchase, when the page is hidden (`visibilitychange`).

## Version the data

* Put a `version` number into each saved value. When the structure changes in a new build, migrate old data on load instead of discarding it — players keep their progress across updates.
* Treat missing or unreadable data as a new player, never as an error that blocks the game.

## Check before uploading

* Play a few levels, reload the page: the game continues from the same point with the same coins and settings.
* Rotate the device and open an ad in the middle of a level: nothing is reset (item 3.2.3).
* Purchased items are still there after a reload — permanent purchases are restored with [`payments.getPurchases()`](/playgama/bridge-sdk/api/payments.md#list-of-purchased-items) (item 2.4.6 of the [Advertising and Payments Requirements](/playgama/game-requirements/advertising-requirements.md)).
* The game's own code and its engine settings contain no `localStorage`, IndexedDB or engine save calls. The Bridge may use browser storage itself on some platforms — that is expected.
