Mini Apps run as sandboxed cross-origin iframes inside the Startale App. This environment imposes browser-level storage restrictions that differ from a normal browser tab. Understanding them upfront prevents silent bugs in production.
What works and what does not
Why cookies fail silently
Mini App URLs are always cross-origin relative to app.startale.com (all Mini Apps are hosted on their own domain). The Startale App embeds them with:
The allow-same-origin flag preserves the Mini App’s own origin (so the Mini App can access its own localStorage), but the frame is still third-party to app.startale.com.
Safari / iOS, Intelligent Tracking Prevention: ITP blocks third-party cookie storage in cross-origin iframes by default. document.cookie = "..." runs without throwing an error, but the cookie is silently dropped or scoped to ephemeral storage that does not survive navigation. This is not a bug in the Startale App; it is Safari’s enforced policy.
Chrome, CHIPS (Partitioned Cookies): Third-party cookies require the Partitioned attribute. Without it, behavior is unreliable and being phased toward full removal.
The key misconception: SameSite=None; Secure controls whether a cookie is sent on cross-site requests. It does not override ITP or Partitioned Cookie policies that block the cookie from being stored in the first place.
localStorage: the recommended approach
localStorage works reliably in the sandboxed iframe because allow-same-origin preserves the Mini App’s origin. Storage is scoped to your Mini App’s origin and is stable across repeated sessions launched from app.startale.com.
Namespace your keys. Use a consistent prefix to avoid collisions between multiple Mini Apps on the same origin:
Saving state on close
The reliable hooks for catching a frame close or navigation are visibilitychange and pagehide. Register them on mount and write to localStorage synchronously inside the handler.
Write synchronously inside pagehide. The browser may freeze the JavaScript thread immediately after the event fires, so async operations including IndexedDB writes are not reliable at this point. Use localStorage.setItem; it is synchronous.
Restore state on mount before calling sdk.actions.ready():
Backend authentication: replace cookies with Bearer tokens
If your Mini App authenticates against a backend API, return the session token in the JSON response body and store it in localStorage. Do not rely on Set-Cookie.
Your backend must accept Authorization: Bearer <token> instead of reading from the Cookie header.
IndexedDB: structured or large data
For structured data, larger payloads, or binary assets, use IndexedDB. It follows the same origin rules as localStorage and works reliably inside the iframe.
Do not write to IndexedDB inside a pagehide handler. IndexedDB operations are asynchronous and will not complete before the browser freezes the thread. Use localStorage.setItem for any state that must be saved on close.