← Field Notes
Published 12 min read

The Browser Opened the Game. Storage Stopped It.

Why a browser-based game that loads successfully can still fail before play, and how to test the real storage budget instead of blaming the network.

In this article
  1. Opening a page is not the same as loading an application
  2. Where does the download actually go?
  3. Browser quota is not just free disk space
  4. A better test matrix for a browser-delivered app
  5. Separate the three failures that look like a stalled download
  6. The smallest useful failure report
  7. Why persistent storage is not a magic fix
  8. Recovering from a half-finished asset download
  9. A release check I would require
  10. What I would ask before self-hosting this
  11. The operational lesson
  12. Sources and further reading
  13. AI transparency

I found a browser game that looked promising for a simple reason: the launcher opened in a browser. No desktop installation, no separate launcher, no obvious dependency on an operating-system package manager.

That sounded perfect for testing what a browser-only setup could do.

The page opened. The game began downloading what it needed. The progress meter climbed into the twenties or thirties, then the browser reported that storage was exhausted. Repeating the attempt did not make the download finish.

I do not have a measured quota from that environment, and I did not inspect the site’s storage implementation. I cannot honestly say whether the application used IndexedDB, the Cache API, the Origin Private File System, or something else under the hood. The observation is narrower: the page loaded, the asset download started, and the game was not playable because the asset-storage step failed.

That one distinction matters more than the fact that the application ran in a tab.

Opening a page is not the same as loading an application

A browser application can have several independent delivery steps:

  1. Fetch the HTML, scripts, styles, and loader.
  2. Initialize its runtime.
  3. Download additional assets, sometimes very large ones.
  4. Store or stage those assets somewhere the runtime can read.
  5. Load enough data into memory to start.
  6. Accept input and complete the actual user workflow.

Only the first two steps need to succeed for a page to look promising.

A site can return HTTP 200, render its controls, and even display an animated progress bar while the thing the visitor came to do remains impossible.

This resembles a lesson I had already learned with remote applications: reachable is not the same as playable. The browser version adds another boundary. A reachable application may still depend on storage that the browser, profile, policy, or device cannot provide.

The server’s capacity and the user’s local browser capacity are different budgets. Moving the application to a faster self-hosted server would not, by itself, increase the space available to the browser running it.

Where does the download actually go?

“Browser-based” is a description of the interface and runtime, not a guarantee that the application is small or self-contained.

A web application might fetch a resource on demand and keep it only temporarily. It might use the Cache API to retain network responses. It might store structured data and binary objects in IndexedDB. It might use the Origin Private File System to manage files within browser-controlled storage. Some games also extract or transform compressed downloads, temporarily needing space for both the compressed and unpacked data.

Those designs have different implications for startup time, repeat visits, cleanup, and recovery.

I cannot attribute any one of those mechanisms to the game I tried. That would require inspection and evidence.

But I can identify the architectural question that the failed download raised: how much storage does a complete first launch require on the actual client, and where is that storage allocated?

A large disk somewhere in the homelab cannot answer that question if the game insists on storing its assets in the client browser.

The browser may also be managed. In that case, the supported troubleshooting path is to record the error and ask the responsible administrator about the approved storage and site policies. An alternate browser profile, policy bypass, or unauthorized software installation is not a legitimate compatibility test.

Browser quota is not just free disk space

The browser manages storage on behalf of each site, usually called an origin. Its estimate of what an origin may use can differ from free disk space and can change with browser implementation, browsing mode, storage settings, and the device.

Modern browsers provide navigator.storage.estimate(), which returns estimated usage and quota values for the current origin. That distinction matters: running the snippet on my own website would measure my site’s storage estimate, not a different game’s origin. The result is useful as a diagnostic signal, not a promise that a write of that size will succeed.

Microsoft’s current Edge documentation makes the distinction concrete. IndexedDB, Cache API, and Origin Private File System storage may have a quota based on a percentage of total disk capacity, while actual free space can be lower. A generous reported quota therefore does not guarantee that the device can complete a large asset download. The exact limit in the environment where I saw the error is unknown.

For a developer-controlled test page in a secure context, the following is a reasonable read-only probe:

async function describeOriginStorage() {
  if (!navigator.storage?.estimate) {
    return { supported: false };
  }

  const { usage, quota } = await navigator.storage.estimate();

  return {
    supported: true,
    estimatedUsageBytes: usage ?? null,
    estimatedQuotaBytes: quota ?? null,
    estimatedRemainingBytes:
      typeof usage === "number" && typeof quota === "number"
        ? Math.max(0, quota - usage)
        : null,
  };
}

console.table(await describeOriginStorage());

This script does not increase the quota or prove what a particular game stores. It only checks what the active origin reports. It should be run where inspection is allowed, not used to work around organizational restrictions or managed-browser controls.

If a storage operation exceeds the applicable limit, supported storage APIs may fail with a QuotaExceededError. That is not necessarily a network failure, even when it appears in the middle of a download.

MDN also documents that quota figures are estimates. Browsers may pad reported usage and impose limits that are not a simple reflection of available disk space.

A better test matrix for a browser-delivered app

I would now test the entire first-run path, not just the launcher. This is a proposed validation plan, not a report that I completed all of these experiments.

BoundaryEvidence I needWhat passing actually proves
Page deliveryEntry page and required scripts loadThe client can reach the launcher
Asset deliveryDownloads complete without transport errorsRequired remote resources can arrive
Local storageStorage writes complete, usage remains within budgetAssets can be staged or retained for this profile
Runtime initializationThe application reaches a usable stateDownloaded resources can initialize
Input and playbackControls work and a short session runsThe intended activity is actually usable
Repeat launchClose, reopen, and verify expected stateCache and persistence assumptions survive one revisit
Clean recoveryDocument how to clear only this site’s disposable dataA failed install can be undone without broad browser cleanup

Separate the three failures that look like a stalled download

A stalled progress bar is not enough to identify the failing subsystem. I would distinguish these cases before proposing a fix:

Failure classEvidence to collect in an authorized testWhy the next step differs
Network or server deliveryFailed HTTP requests, response status, interrupted transfer, or server logsInvestigate the delivery path, not browser storage first
Browser storage writeExplicit quota or storage error, storage API failure, or origin usage estimateInvestigate capacity, incomplete stored data, and application recovery behavior
Runtime or memory initializationAssets arrive but initialization crashes, hangs, or reports an allocation errorInvestigate memory demand and runtime compatibility, not the disk quota alone

A message about storage is evidence worth prioritizing, but without browser diagnostics or application logs it is not proof of the exact storage API or internal failure mode. This is a proposed diagnostic framework, not a claim that I captured all three classes during the original attempt.

A percentage indicator is weak evidence by itself. Twenty-five percent of “download” could mean a quarter of compressed bytes, a quarter of files, or an arbitrary phase weight. Without implementation details it is not a measurement of storage consumption.

The real failure point belongs in the test record: the displayed progress, the exact error wording, the browser and profile type where disclosure is appropriate, and whether the problem occurs on a fresh permitted test profile. Record the observation before inferring the cause.

The smallest useful failure report

If the problem is in an application I do not control, the fastest next step is a reproducible report to its maintainer. A progress percentage alone cannot distinguish a broken download from a failed write.

I would record:

  • Expected result: the first playable action, not merely a visible launcher.
  • Actual result: the exact error text and the stage where it appeared.
  • Reproduction: a short sequence of permitted steps, including whether the issue repeats.
  • Environment: browser family and version, device class, and whether the profile is managed, when sharing that information is permitted.
  • Evidence: relevant application error output or a sanitized developer-console message, if diagnostics are authorized.
  • Unknowns: the asset size, actual browser quota, storage API, and whether incomplete data remains, unless measured.

Do not attach full browser profiles, session cookies, access tokens, private URLs, or employer-specific policy details. If the browser is managed and developer tools are restricted, the report can state that diagnostics were unavailable. An honest limitation is more useful than a guessed root cause.

That report gives the maintainer a testable starting point. It does not pretend the application has been debugged just because a plausible explanation exists.

Why persistent storage is not a magic fix

The Storage API also provides navigator.storage.persist(). That asks the browser to protect an origin’s data from some forms of automatic eviction.

It does not grant unlimited storage. It does not guarantee a larger quota, bypass a managed policy, create extra disk space, or remove the need to handle write failures.

Persistence is a durability tool. Quota is a capacity constraint. Treating them as the same problem sends troubleshooting in the wrong direction.

A site that fails during its initial download needs a supported data path that fits the available client budget. Making stored data less likely to be evicted later does not solve an asset package that cannot fit in the first place.

Recovering from a half-finished asset download

The failure I observed did not produce a playable installation. I did not verify whether the launcher had left partial data behind. A failed write may create recoverable or disposable artifacts, but neither their presence nor their size was measured in this case.

If I controlled the application, I would design recovery as part of its first-run path:

  1. Record the failing stage. Log the asset, operation, and error without logging credentials or private browsing data.
  2. Separate temporary and committed assets. Download into an identifiable staging area; record an asset as installed only after required integrity checks pass.
  3. Make retries idempotent. Reuse verified assets rather than retaining duplicate partial downloads after each attempt.
  4. Handle quota errors where the write fails. Explain which operation failed and whether the app supports cleanup or a smaller asset package.
  5. Offer narrowly scoped cleanup. Delete known incomplete items, not every piece of data for the site.
  6. Re-test a complete launch. The proof is a usable session and a repeat launch, not a refreshed quota estimate.

For a third-party game, those are design requirements to ask the maintainer about, not console commands to run against a site I do not control. Clearing an entire origin can destroy saves, preferences, and offline assets. Clearing a browser profile is broader still. Back up exportable game data before using a supported reset feature.

An estimate() value is not an allocation reservation, and persistence does not grant extra capacity. If the required assets will not fit in a managed environment, a smaller supported asset set, an authorized different delivery design, or an explicit incompatibility notice is better than repeated retries.

A release check I would require

I would sign off on a browser-delivered game only after documenting the first useful action and what it takes to reach it. For a small arcade game, that could be starting a round and saving one result. For an asset-heavy game, it means completing the required download, initializing the runtime, and playing a short session.

The release record should say what was actually tested, which browser family was used, and whether repeat visits depend on retained local data. Server uptime, browser storage, and application memory are three separate constraints. A healthy deployment dashboard does not establish a healthy first-run experience.

What I would ask before self-hosting this

If I were going to host or adapt a browser app for people other than myself, I would ask:

  • What must download before the first useful interaction?
  • How many bytes are transferred, stored, unpacked, and held in memory?
  • Can assets stream or load in smaller, independent stages?
  • Can the client choose a smaller content package?
  • Is a failed download resumable without duplicating storage?
  • What happens when a write fails halfway through?
  • Is the failure message actionable, or does it just say “no storage”?
  • Can the app clear its own incomplete files safely?
  • Does a successful launch survive closing and reopening the tab?
  • Does the target browser actually permit this storage mechanism?

Some of these questions require inspecting application source or measuring a permitted test environment. They are requirements and open questions, not claims that the game I tested satisfies them.

For a small browser arcade, I would rather launch a compact, self-contained game reliably than place a much larger game behind a beautiful loader that never reaches a playable state.

That is not an argument against ambitious web software. It is an argument for including the client’s storage and runtime constraints in the deployment design.

The operational lesson

I used to think of browser compatibility mainly as rendering and input: does the page look right, and do the controls work?

This attempt put an earlier requirement in front of both.

A browser can be capable of rendering an application while being unable to complete its asset installation. The user experiences that as a broken game. The developer may see a successful website deployment. Both observations can be true.

It is the same release-validation principle I wrote about in The Build Passed. Production Did Not Move.: passing one handoff does not prove the final outcome.

Next time I evaluate a browser-only application, I will ask about client storage before treating the visible launcher as evidence of compatibility.

The page opened. That was all it proved.

Sources and further reading

AI transparency

AI assisted with research organization and editorial drafting. The partial first-run asset download and storage failure are observed; the storage API details come from the documentation linked above. The app’s internal storage implementation, precise quota, and recovery path have not been measured or tested.

JO

Written by

Jessie Owens

I run Eldritch IT and write about the systems, repairs, infrastructure decisions, and business lessons behind the work.