Listen for the visibilitychange event (state ‘hidden’) and the pagehide event, then run your save function immediately and synchronously. Do not rely on beforeunload for mobile browsers. Save to storage that survives tab closure, not sessionStorage, and keep the write small and fast.
At a glance
| Fact | Value | Source |
|---|---|---|
| Event that fires on tab backgrounding | visibilitychange | developer.mozilla.org |
| sessionStorage survives tab close | no, destroyed | developer.mozilla.org |
| Godot pauses when tab inactive | true, by browser | docs.godotengine.org |
Attach a listener to document.addEventListener('visibilitychange', ...) and check document.visibilityState === 'hidden' – this fires reliably when a tab is backgrounded or closed, on desktop and mobile. Also listen for pagehide, which fires on tab close and is more consistent on mobile browsers than beforeunload. Call your save function synchronously in both handlers; don’t queue an async request that might not finish before the page is torn down.
Where you save matters as much as when. MDN notes that closing the browser tab destroys all sessionStorage data associated with that tab, so sessionStorage is the wrong place for progress you want to keep. Use localStorage or, for cross-device persistence, a cloud save API. For multi-platform games, the Playgama Bridge Storage module picks the most suitable storage automatically, including cloud saves where available (see the Bridge guide).
What about the game engine’s own pause behaviour?
- Unity WebGL: hook the browser event through a .jslib plugin that calls back into your save method when visibilitychange fires.
- Godot 4: use the JavaScriptBridge singleton to bind the same browser event; Godot’s own docs say the project will be paused by the browser when the tab is no longer active, so trigger the save just before that pause, not after.
- Keep the save payload small – write only changed fields, not the whole game state, so it completes before the tab is gone.
If storage is temporarily unavailable, treat it like an empty result and continue the game with in-memory defaults rather than blocking; retry the write on the next natural save point.
Sources
- MDN: Web Storage API
- Godot docs: exporting for the Web
- Unity manual: interacting with browser scripting
- Playgama Bridge Storage API
- Playgama Bridge getting started
Related questions
Should I use beforeunload for autosave?
Avoid relying on it alone; it is unreliable on mobile browsers. Use visibilitychange and pagehide as the primary triggers on desktop and mobile.
Is sessionStorage safe for autosave?
No. Closing the tab destroys all sessionStorage data tied to that tab, so any progress saved there is lost when the player leaves.
What if the storage write fails when the tab closes?
Treat a missing or empty result as a normal case: keep sensible defaults in memory and retry the save on the next natural checkpoint rather than blocking gameplay.
Last updated: 24 September 2026