Skip to main content
Supported on
Snapchat

Storage

The storage capability is a small key-value store for your Lens, tied to the player's Snapchat account. It keeps data between launches, unlike localStorage and IndexedDB, which start empty every time the Lens opens.

Check snapchat.isSupported('storage') after init() resolves, and keep the game playable without storage. isSupported() returns false until then, so a check at page load always reads as unsupported.

Limits​

Each Lens has its own store for each player.

LimitValue
ValueAny JSON value, up to 32 KiB
KeyA string of 1 to 256 bytes
Total size100 KiB
Number of keys256

A write that would go over a limit rejects with ERR_QUOTA_EXCEEDED and leaves the store unchanged, so the previous value is still there. getInfo() reports how much of each limit the store uses.

Snapchat also limits how many storage calls can be in flight at once. A burst, such as a write every frame or a parallel write for each field, rejects with ERR_QUOTA_EXCEEDED however small the data is. Save when the state changes, and chain writes through one promise, as in the save game recipe.

Read and write​

const result = await snapchat.storage.get('save');
const save = result.found ? result.value : { level: 1, coins: 0 };

await snapchat.storage.set('save', { level: 3, coins: 120 });
  • get() resolves with found, which tells a missing key apart from a stored null.
  • set() replaces any previous value.
  • remove() deletes one key, and resolves even if the key doesn't exist.
  • clear() deletes the Lens's whole store for the current player.
  • keys() lists the stored keys, which is useful for save slots:
const { keys } = await snapchat.storage.keys();
const slots = keys.filter((key) => key.startsWith('slot:'));

When data doesn't persist​

  • ERR_STORAGE_UNAVAILABLE means there's no durable storage on this device or in this session, or that the Lens is closing, as when a save fires while the Snapchatter swipes it away.
  • The desktop stub keeps storage in memory, so it's gone after a reload. getInfo() reports persistenceMode: 'memory' there, and 'disk' where data persists.
const { persistenceMode } = await snapchat.storage.getInfo();
if (persistenceMode === 'memory') {
console.warn('Progress will not survive a restart here');
}

Save game​

The first storage call of a session opens the store, and on a cold start it can take seconds. Await it behind a loading state rather than timing it out, and write nothing until it answers: a write before then replaces the save that's still being read.

Save when the state changes and when the page is hidden, because Snapchatters close a Lens with a swipe and the page gets no other warning. Chain the writes through one promise, so only one is in flight:

let loaded = false; // no writes until the first read has answered
let pending = Promise.resolve();

// If the first read fails, saving stays off for the session rather than writing over a save it couldn't read.
async function loadSave() {
if (!snapchat.isSupported('storage')) return null;
await pending; // a later re-read waits for queued saves to land
try {
const result = await snapchat.storage.get('save');
loaded = true;
return result.found ? result.value : null;
} catch (e) {
console.warn('No save:', e.message); // for example, ERR_STORAGE_UNAVAILABLE
return null;
}
}

// Resolves true once the save lands, false if it was refused or saving is off.
function writeSave(state) {
if (!loaded) return Promise.resolve(false);
// Handling the rejection keeps the chain alive: one failed save must not reject every save after it.
pending = pending
.then(() => snapchat.storage.set('save', state)) // any JSON up to 32 KiB
.then(
() => true,
(e) => {
console.warn('Save failed:', e.message); // the previous save is unchanged
return false;
}
);
return pending;
}

// gameState is your game's current progress, the same value you pass to writeSave() as it changes.
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') writeSave(gameState);
});

A get() answers for the account signed in at that moment, so a value read at startup is a copy. Write what changed as it changes, rather than writing that copy back later over saves made since.

StorageAPI in the API reference lists every parameter and return value.

Was this page helpful?
Yes
No