The Storage Manager
navigator.storage
Section titled “navigator.storage”The navigator.storage object is the entry point to the Storage Manager API. It gives you visibility into how much disk space the current origin is consuming, what quota the browser has granted, and whether the origin’s data is protected from eviction.
All three methods are async and return Promises.
navigator.storage.estimate()
Section titled “navigator.storage.estimate()”Returns a Promise that resolves to an object with two properties:
usage— the number of bytes currently used by the origin across best-effort storage mechanisms (Cache API, IndexedDB, OPFS, etc.) — it does not includelocalStorage/sessionStorageor cookies, which have their own separate, much smaller limitsquota— the maximum number of bytes the browser is willing to grant to this origin
Both values are in bytes and are estimates. The browser may round or cap them for privacy reasons.
const { usage, quota } = await navigator.storage.estimate();
const usageMB = (usage / 1024 ** 2).toFixed(2);const quotaMB = (quota / 1024 ** 2).toFixed(2);
console.log(\`Used: \${usageMB} MB of \${quotaMB} MB available\`);Quota is dynamic — it varies based on how much free space is available on the device. On mobile devices with limited storage, the quota may be much smaller than on desktop machines.
navigator.storage.persist()
Section titled “navigator.storage.persist()”Requests that the browser grant persistent storage to the current origin. Returns a Promise that resolves to true if the request was granted, or false if the browser declined.
const granted = await navigator.storage.persist();console.log('Persistent storage granted:', granted);Whether the browser grants persistence depends on browser heuristics, such as whether the user has added the site to their home screen, how often the user visits, or whether the user explicitly approved a permission prompt. You cannot force it to return true.
navigator.storage.persisted()
Section titled “navigator.storage.persisted()”Checks whether the current origin already has persistent storage. Returns a Promise that resolves to true if storage is currently persistent, or false if it is best-effort.
const isPersistent = await navigator.storage.persisted();
if (isPersistent) { console.log('Data is safe from automatic eviction');} else { console.log('Data may be evicted under storage pressure');}Use persisted() at app startup to determine whether you need to show a “please allow persistent storage” prompt to the user.
Runnable: estimate and check persistence
Section titled “Runnable: estimate and check persistence”Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
Calling estimate() before caching a large amount of data | Know the remaining quota in advance, avoiding a mid-write failure | It’s only an estimate — the browser may round the numbers to resist fingerprinting, so it isn’t 100% precise |
Calling persist() to prevent eviction | Data isn’t automatically deleted when disk space gets tight — good for an offline app | Depends on the browser’s own heuristics for approval, and adds a little friction to the app’s startup flow |
| Using best-effort storage without requesting persistence | Zero friction — no condition to wait on | Risks eviction with no advance warning |
Common mistakes
Section titled “Common mistakes”- Not checking
navigator.storage.persisted()before assuming data is safe — callingpersist()once doesn’t always mean it succeeded; verify the actual result before relying on it. - Assuming
estimate()’susagecoverslocalStoragetoo — it only covers best-effort storage (Cache API, IndexedDB, OPFS);localStorage/sessionStorageand cookies have their own separate, much smaller quotas and never show up in this number. - Caching many opaque responses and being surprised the quota runs out fast — an opaque response is counted at its true full size (often several MB each) toward usage, even though its body can’t be read.