Website-Pflichtencheckby Jurono
WebsiteTechnicalCodeMaintenancePerformance

Offline Does Not Mean Durable: Auditing Browser Storage

IndexedDB, Cache Storage, and OPFS can retain data for a long time without guaranteeing it forever. Audit quotas, persistence, eviction, synchronization, and recovery.

By Jurono
Updated: September 20, 2026

A field-service app stores forms offline. An editorial system keeps drafts locally until connectivity returns. A SaaS product places files or search indexes in IndexedDB or the Origin Private File System. In testing, everything survives reloads and even browser restarts.

Then a user reports: “My draft is gone.”

The instinctive response is often: “But we store it in IndexedDB.”

That is the misunderstanding. Browser storage is not automatically durable application storage. The web platform distinguishes between best-effort and persistent storage. Best-effort is the normal mode: data can survive across sessions, but it is not guaranteed against quota limits, storage pressure, browser policy, or explicit deletion by the user.

That is perfectly acceptable for disposable caches. For the only copy of a contract draft, an unsynchronized order, or an offline work report, it becomes an architecture question.

Myth: If it survives a reload, it is persistent

localStorage, IndexedDB, Cache Storage, and OPFS can retain data across reloads and browser restarts. That proves only that the data has not been removed yet.

The WHATWG Storage Standard defines a common storage architecture, quota estimates, and a mechanism for requesting persistent storage. By default, however, an origin normally operates with best-effort storage. Under storage pressure, the browser may evict non-persistent origin data.

Three properties should therefore be considered separately:

  • Session-durable: data may survive tabs and restarts.
  • Persistent storage: the browser has granted stronger protection against automatic eviction.
  • Server-backed: another copy exists outside this browser profile.

Those are not the same guarantee.

The storage budget is bigger than IndexedDB

One origin may simultaneously use IndexedDB for records, Cache Storage for responses and offline assets, OPFS for files, localStorage for small key-value data, and service-worker-related state.

Operationally, that means an application does not consume quota only with business data. A large offline cache, thumbnails, or downloaded files can compete with important local records for finite device storage. “Our IndexedDB is only 30 MB” is therefore not a complete capacity analysis.

Red flag 1: Nobody knows current usage or quota

navigator.storage.estimate() lets an application request an estimate of current usage and quota. The word estimate matters: these values are not a permanent allocation. Quotas vary by browser, device, free disk space, and browsing mode, and can change.

The API is still useful. An offline app that starts a large download without checking whether roughly enough space is available turns a predictable condition into a surprise failure.

Useful product logic can check quota before large writes, define warning thresholds, clear expendable cache data first, and explain when an offline package cannot be stored completely.

Red flag 2: QuotaExceededError exists only in documentation

When a write exceeds available quota, storage operations can fail. MDN documents QuotaExceededError for technologies such as IndexedDB, Cache Storage, and OPFS.

A resilient client treats that as a real operational state: writes have explicit error handling, a record remains visibly unsaved or unsynchronized, the UI does not report success before the write completes, and expendable data can be removed deliberately.

A dangerous pattern is a button turning green, a dialog closing, and an asynchronous storage write failing in the background. Technically, an exception occurred. From the user's perspective, the product broke a promise.

Red flag 3: Critical data exists only locally

Browser storage can be the right foundation for a deliberately local-first application. But local-first still needs an answer for loss, conflicts, and recovery.

For many SaaS products, a useful rule is: data whose loss would hurt the business should not remain indefinitely as the only copy inside one browser profile.

A draft can originate offline. Once connectivity returns, a defined synchronization path should take over. Depending on the product, that includes stable local identifiers, server versions, retries, conflict handling, idempotent synchronization, and visible sync status.

A green “Saved” indicator should distinguish “saved locally” from “backed up to the server.” Those states should not look identical when their risk is different.

Red flag 4: Persistence is never checked

The Storage API provides navigator.storage.persisted() to check whether an origin already has persistent storage. navigator.storage.persist() can request it.

The request is not a command. Browsers apply their own rules when deciding whether to grant persistence, so the application must remain correct when the result is false.

Persistent storage also should not be requested reflexively on the first page view. A more meaningful moment is when the user enables a feature whose local data genuinely matters, such as “Make available offline” or saving work that has not yet synchronized.

Red flag 5: Private browsing has never been tested

Private or incognito browsing is a separate test case. Browsers may apply different quotas there, and locally stored data is generally removed when the private session ends.

An app that works perfectly offline in a normal profile can receive less storage in private mode, handle persistence differently, and lose all local data when the session ends. That is not necessarily a browser bug. It becomes a product bug when the interface still promises durable offline availability.

Cache data and irreplaceable data need different priority

A downloaded thumbnail can be regenerated. An unsynchronized draft may not be. Yet both are often put into the same implicit risk category: “stored locally.”

A better model classifies data:

  • Regenerable: bundles, images, API caches, search indexes. Loss costs time or bandwidth, not business records.
  • Synchronized: local copies of data already safely stored on the server.
  • Not yet synchronized: drafts, inputs, recordings, or work states that exist only on this device. This class deserves the highest priority and rapid synchronization.
  • Intentionally local: data that deliberately never goes to the server. If loss is unacceptable, the product needs an explicit export, backup, or recovery strategy.

This classification is often more useful for architecture than “IndexedDB or OPFS?”

Browsers differ — so a fixed GB number is the wrong requirement

WebKit documents a device-capacity-based quota model and conditions under which best-effort origins can be evicted. Chrome and other browsers apply their own quota policies. MDN documents these differences across implementations.

A robust requirement is therefore not: “We always have 5 GB.” It is: we can estimate the current quota, detect failed writes, free expendable data, recover critical data, and degrade offline features clearly when storage is unavailable.

What a useful storage audit tests

A real audit goes beyond “Does IndexedDB exist?” It checks:

  1. Data inventory: What lives in IndexedDB, Cache Storage, OPFS, and localStorage? What is regenerable, synchronized, or unique?
  2. Quota and growth: How much space is consumed after a day, a month, or a hundred offline records?
  3. Failure paths: What happens on QuotaExceededError, interrupted writes, or low disk space? Does the UI remain truthful?
  4. Persistence state: Is persisted() checked? Is there a meaningful moment for persist()? Does the product still work if persistence is denied?
  5. Synchronization: What happens after long offline use, multiple devices, or server-side changes?
  6. Deletion and recovery: Does the app recover cleanly after Clear site data, a profile change, or eviction?
  7. Migrations: Does a new release work with an old, populated IndexedDB rather than only with a clean developer profile?

Test loss deliberately

The most valuable browser-storage test is not “reload and the data is still there.” Test almost-full storage, a large offline dataset, persistence granted and denied, private browsing, deleted site data, offline writes followed by reconnect, and a new release against an existing local database.

The goal is not to prevent every browser storage decision. You cannot. The goal is to avoid turning storage loss into application chaos.

What Website-Pflichtencheck would inspect

For a web app using local storage, Website-Pflichtencheck would review the actual storage mechanisms, data classes, usage and quota, persistence state, write error handling, offline synchronization, cache cleanup, private browsing behavior, schema upgrades, and recovery paths.

This matters especially for products that promise “works offline,” “drafts are saved automatically,” or “we will sync later.” Those statements are not merely UX copy. They imply a technical durability guarantee that should be testable.

Browser storage is powerful. IndexedDB, Cache Storage, and OPFS enable very capable web applications. But available locally does not automatically mean durably backed up. Model that boundary deliberately and users can tell what exists only on this device, what has synchronized, and what can be recovered after failure.

Jurono logo

Jurono

Technical website audits, website fixes, and AI code rescue for small businesses, practices, law firms, and founders in Germany.

Get our free security checklist before you go.

Download free PDF

Want a first signal in 30 seconds? Run the free website quick test.

Get website notes by email

One short technical note every two weeks. No spam, no sales pitch.

Matching offers

Move forward directly

Based on the topics in this article — without a long search.

Manual Website Check

When nobody is sure which scripts, cookie signals, or technical risks are currently running on the site.

249

Manual technical first assessment and clear priorities within two business days.

  • Quickly see whether tracking, cookies, external services, or HTTPS look suspicious
  • Mobile, load time, and technical issues explained in plain language
  • The most important points in a short priority list
Secure Manual Website Check

Technical Website Audit

When the website matters, but nobody knows which visible required areas, technical risks, and fixes actually have priority.

549

Audit, assessment, and concrete action plan within 3-5 business days.

  • Everything from the manual website check, assessed and documented in more depth
  • Concrete findings for cookie, tracking, and external service signals
  • Visible required areas checked technically, without legal advice
Request Technical Website Audit

AI Code Triage

When the project starts, but nobody knows why it keeps breaking.

390

Code review, build/import check, and rescue plan within two business days.

  • Repository check for broken imports, missing packages, and build errors
  • Assessment: repair, restructure, or discard
  • Prioritized fix list with effort estimate
Request AI Code Triage

Get clarity before you commit to fixes.

Start with a technical check. If the findings are minor, you can stop there, hand the report to your existing team, or book targeted fixes later.

Technical audit and implementation, not legal advice. I check visible signals, integrations, and delivery issues; legal texts and binding legal assessments remain the work of lawyers or privacy consultants.

Offline Does Not Mean Durable: Auditing Browser Storage