from quota calculation to persistence requests
The Storage Manager API answers two questions that every offline application eventually faces: how much storage space is actually available to the origin, and how do you prevent the browser from simply deleting that data under storage pressure. Anyone who correctly uses quota calculation and persistence requests builds applications that avoid data loss proactively instead of explaining it after the fact.
Table of Contents
- 1. Why the Storage Manager API is a blind spot for many web apps
- 2. Computing quota and usage with estimate()
- 3. UsageDetails: a breakdown by storage type
- 4. Best effort versus persistent storage
- 5. How browsers decide on persistence requests
- 6. A proactive warning system against running out of space
- 7. Quota management across multiple storage APIs
- 8. Browser differences and testability
- 9. Storage Manager API compared to manual approaches
- 10. Summary
- 11. FAQ
1. Why the Storage Manager API is a blind spot for many web apps
The Storage Manager API is available through navigator.storage in every modern browser, yet it is completely ignored in most applications. Developers happily write data with IndexedDB, Cache Storage or the Origin Private File System without ever checking how much space is actually left, or whether the browser might evict that data at any time under storage pressure. The Storage Manager API closes exactly that gap with two central methods: estimate() for quota calculation and persist() for persistence requests.
The problem becomes visible as soon as an application grows: a photo editor caching images in the Origin Private File System, an offline shop keeping product catalogs in IndexedDB, or a PWA holding assets in Cache Storage, all compete for the same share of storage space the browser allocates to the origin overall. Without the Storage Manager API, the application only learns about a bottleneck once a write operation fails with a QuotaExceededError, usually at an inconvenient point in the flow.
The Storage Manager API flips that reactive pattern around: instead of waiting for an error, the application can proactively query how much storage is available, how much is already used, and whether the data is durably protected. For data intensive web applications, the Storage Manager API is therefore not an optional detail but a basic prerequisite for robust storage management.
2. Computing quota and usage with estimate()
The method navigator.storage.estimate() is the central entry point of the Storage Manager API. It returns a promise that resolves with an object containing at least two fields: quota, the estimated maximum amount of storage available to the origin, and usage, the amount currently used across all storage APIs. Both values are given in bytes and allow a simple calculation of the remaining headroom.
Important for correct use of the Storage Manager API: the quota value is an estimate, not a fixed guarantee. It depends on available disk space, the number of other origins on the same device, and internal browser heuristics. Chrome, for example, typically computes quota as a share of free disk space, while Firefox manages a group quota across several origins. The Storage Manager API abstracts these differences and, in every case, delivers a consistent, up to date estimate.
// Core Storage Manager API usage: query quota and current usage
async function getStorageReport() {
if (!navigator.storage || !navigator.storage.estimate) {
return { supported: false };
}
const { quota, usage } = await navigator.storage.estimate();
const percentUsed = quota > 0 ? (usage / quota) * 100 : 0;
return {
supported: true,
quotaBytes: quota,
usageBytes: usage,
remainingBytes: quota - usage,
percentUsed: percentUsed.toFixed(2),
};
}
const report = await getStorageReport();
console.log(`Using ${report.percentUsed}% of ${report.quotaBytes} bytes quota`);
In practice, it pays off to query the Storage Manager API regularly, for instance at application startup and before larger write operations, rather than calling it just once on first load. Since the available storage space can change due to other applications on the same device, a single query quickly returns stale values. A recurring check through the Storage Manager API, for example every few minutes or before critical writes, keeps the assessment current.
3. UsageDetails: a breakdown by storage type
Some browsers, particularly Chromium based ones, extend the result of estimate() with a usageDetails object that breaks down total usage by storage type: indexedDB, caches, serviceWorkerRegistrations and other fields show which mechanism accounts for which share of the quota. This level of detail is not standardized and therefore not available in every browser, but it is extremely helpful for debugging and capacity planning.
With the usage details of the Storage Manager API, you can, for example, discover that an application unexpectedly consumes a lot of space through old cache entries while IndexedDB only accounts for a small fraction. Without this breakdown, a team would only see the total sum and would have to guess which storage mechanism needs cleaning up. The Storage Manager API thus provides the data basis for targeted cache invalidation instead of a blanket "delete everything".
// Break down usage by storage mechanism (Chromium-based browsers)
async function getUsageBreakdown() {
const estimate = await navigator.storage.estimate();
if (!estimate.usageDetails) {
return { breakdown: null, total: estimate.usage };
}
const breakdown = Object.entries(estimate.usageDetails)
.sort(([, a], [, b]) => b - a)
.map(([mechanism, bytes]) => ({
mechanism,
megabytes: (bytes / (1024 * 1024)).toFixed(2),
}));
return { breakdown, total: estimate.usage };
}
const { breakdown } = await getUsageBreakdown();
breakdown?.forEach((entry) => {
console.log(`${entry.mechanism}: ${entry.megabytes} MB`);
});
4. Best effort versus persistent storage
The second central pillar of the Storage Manager API is its persistence model. By default, browsers treat data in IndexedDB, Cache Storage or the Origin Private File System as best effort, meaning: under storage pressure, for example when the disk is almost full, the browser may automatically delete data belonging to rarely visited origins without asking the user. For a note taking app that might be acceptable, but for an application holding irreplaceable user data it is a serious risk.
With navigator.storage.persist(), the Storage Manager API provides a mechanism to move data into persistent mode. If the request is granted, the browser guarantees that the data will only be deleted through explicit user action, for example through browser settings. The call navigator.storage.persisted() checks the current status without triggering a new request, which is well suited for a status check at application startup.
// Storage Manager API: check and request persistent storage mode
async function ensureDurableStorage() {
if (!navigator.storage || !navigator.storage.persist) {
return { durable: false, reason: "not-supported" };
}
const alreadyPersisted = await navigator.storage.persisted();
if (alreadyPersisted) {
return { durable: true, reason: "already-persisted" };
}
const granted = await navigator.storage.persist();
return {
durable: granted,
reason: granted ? "granted-now" : "denied-by-browser",
};
}
const result = await ensureDurableStorage();
if (!result.durable) {
console.warn("Data may be evicted under storage pressure:", result.reason);
}
5. How browsers decide on persistence requests
Unlike permissions for camera or location, the Storage Manager API normally shows no visible dialog for persist(). The decision is instead based on internal heuristics that are weighted differently depending on the browser: whether the page was added to the home screen, whether a push subscription exists, how high the site engagement score is, how often the user visits the origin. Chrome, for example, grants persistence noticeably more often once the web app has already been installed as a PWA.
This invisible heuristic makes the Storage Manager API somewhat unpredictable in practice: a request can be denied on the first visit and automatically granted on the second visit, after the user has used the page several times. For teams this means: a single request on first load is not enough. It is more sensible to re-check the persistence request through the Storage Manager API at every application start and re-issue it when needed, without disturbing the user.
Firefox behaves differently and under certain circumstances actually shows a permission dialog, while Safari does not yet fully support the persistence request of the Storage Manager API and instead uses its own mechanisms for storage space management. This fragmentation means production code always has to account for the case that persist() either does not exist, denies immediately, or grants immediately.
6. A proactive warning system against running out of space
Instead of waiting for a QuotaExceededError, the Storage Manager API can be used to build a warning system that informs users in time, before critical write operations fail. Such a system checks the remaining storage space at regular intervals and, once a defined threshold is reached, for example 90 percent usage, triggers a user notification or an automatic cleanup of old data.
A well designed warning system built on the Storage Manager API combines several signals: the current percentage from estimate(), the persistence status from persisted(), and optionally the breakdown from usageDetails, so that instead of just telling the user "storage is running low" it can suggest concretely which data could be deleted. This combination turns a technical API query into a usable product feature.
// Proactive storage pressure monitor using the Storage Manager API
class StorageWatchdog {
#warningThreshold = 0.85;
#criticalThreshold = 0.95;
async checkAndReport() {
const { quota, usage } = await navigator.storage.estimate();
const ratio = usage / quota;
if (ratio >= this.#criticalThreshold) {
return { level: "critical", ratio, message: "Storage almost full, cleanup required" };
}
if (ratio >= this.#warningThreshold) {
return { level: "warning", ratio, message: "Storage usage is high" };
}
return { level: "ok", ratio, message: "Storage usage is healthy" };
}
startMonitoring(intervalMs = 60000, onStatus) {
const tick = async () => onStatus(await this.checkAndReport());
tick();
return setInterval(tick, intervalMs);
}
}
const watchdog = new StorageWatchdog();
watchdog.startMonitoring(60000, (status) => {
if (status.level !== "ok") console.warn(status.message, status.ratio);
});
7. Quota management across multiple storage APIs
An important aspect of the Storage Manager API: the quota applies origin wide, not per individual storage technology. That means IndexedDB, Cache Storage, the Origin Private File System and even service worker registrations share the same pool of storage space. An application that aggressively caches images in Cache Storage can thereby squeeze the space that was actually intended for the IndexedDB database.
For clean quota management through the Storage Manager API, a central place in the code that coordinates all storage writes and checks before larger operations whether enough headroom exists is recommended. Instead of letting every component write to IndexedDB or Cache Storage independently, a shared storage coordinator should consult the Storage Manager API, set priorities between data types, and, when in doubt, clean up older, less important cache entries first.
8. Browser differences and testability
Although the Storage Manager API is standardized in specification, its concrete numbers differ noticeably between browsers. Chrome usually returns generous quota values, often several gigabytes, while Firefox calculates more conservatively and shares the quota through a group arrangement with other origins. In DevTools, the Storage Manager API can be tested with throttled quota values: Chrome DevTools offers a storage pressure simulation under "Application > Storage" that lets you deliberately provoke your own application's behavior under a QuotaExceededError.
For automated tests, it is advisable to mock the Storage Manager API instead of relying on real browser quota, since it varies significantly depending on the test environment and available disk space. Mocking navigator.storage.estimate to return fixed values makes tests for the warning system and quota logic deterministic and independent of the test runner's actual disk usage.
9. Storage Manager API compared to manual approaches
Many older applications try to solve storage space problems without the Storage Manager API, for example through try catch around every write operation or through fixed, arbitrary limits in the application code. The following table shows why the native Storage Manager API is the more robust solution in almost all cases.
| Task | Manual approach | Storage Manager API | Benefit |
|---|---|---|---|
| Checking available space | Fixed limit in code | navigator.storage.estimate() |
Real, device dependent values instead of guessing |
| Data loss under storage pressure | No control possible | navigator.storage.persist() |
Explicit persistence guarantee attainable |
| Errors when storage is full | Try catch after the failure | Proactive warning system via Storage Manager API | User is informed before the error occurs |
| Usage by storage type | Manual tracking per module | estimate().usageDetails |
Central, automatically current breakdown |
| Checking persistence status | No reliable option | navigator.storage.persisted() |
Immediate, reliable status query |
The Storage Manager API replaces guesswork with hard numbers. A manual approach with fixed limits is always either too conservative, wasting unused storage space, or too optimistic, leading to data loss. The Storage Manager API is the only source that actually knows how much space is available on the user's specific device.
Mironsoft
JavaScript architecture, offline storage and performance engineering
Avoid data loss under storage pressure before it happens?
We implement quota monitoring and persistence strategies with the Storage Manager API, from proactive warning systems to coordinated storage management across multiple APIs.
Quota audit
Analysis of current storage usage and risk assessment for data loss
Persistence strategy
Using persistence requests and engagement signals deliberately for a higher grant rate
Warning systems
Implementing proactive storage notifications and automatic cleanup
10. Summary
The Storage Manager API closes a critical gap in nearly every offline capable web application: knowledge of available storage space and control over whether data is durably protected. With estimate(), quota and usage can be queried at any time, with persist() and persisted() the persistence status can be actively influenced and checked. The optional breakdown through usageDetails additionally provides the data basis for targeted cleanup instead of blanket deletion.
Anyone who consistently integrates the Storage Manager API into an application replaces reactive error handling after a failed write with proactive monitoring that informs users in time and prevents data loss before it occurs. Especially for applications with large data volumes in the Origin Private File System, in IndexedDB or in Cache Storage, the Storage Manager API is therefore not a nice to have but a basic prerequisite for reliable storage management.
Storage Manager API — the essentials at a glance
Compute quota
navigator.storage.estimate() returns quota, usage and optionally usageDetails by storage type.
Secure persistence
persist() requests durable storage, persisted() checks the current status without a new request.
Proactive not reactive
Regular checks with thresholds prevent QuotaExceededError instead of handling it after the fact.
Origin wide quota
All storage APIs share the same pool of space, coordinated management is necessary.