Skip to content

Ask the browser to keep saved work, and warn when it may clear it - #438

Merged
ianarawjo merged 1 commit into
mainfrom
claude/browser-storage-persistence
Sep 16, 2026
Merged

ianarawjo merged 1 commit into
mainfrom
claude/browser-storage-persistence

Conversation

@ianarawjo

Copy link
Copy Markdown
Owner

Asks the browser not to clear ChainForge's saved work when it runs without a local server, and tells people when their work isn't protected, so they can export it.

Why

Without a local server, ChainForge keeps everything in the browser:

  • Flow and responses: in localStorage.
  • Uploaded and generated files: in IndexedDB.

Browsers treat both as "best effort" by default:

  • Low disk space: any browser may clear them.
  • Safari: deletes everything a site's scripts stored after 7 days of Safari use without visiting that site.

Nothing requested persistent storage or warned about this, so browser-only users could lose flows and images without notice. Local installs (chainforge serve, the Mac app) aren't affected: flows and files are saved to disk.

What changed

  • Requesting persistence: navigator.storage.persist() is called the first time someone saves work in a session:

    • a manual Save or Ctrl+S (not autosave);
    • uploading or generating a file kept in the browser.

    It's never called on page load, since Firefox asks the user; the prompt should follow something they did. It's requested at most once per session, and checking the current state never prompts.

  • Notice: if storage isn't protected, a dismissible notice appears below the toolbar with an Export flow button. It explains why:

    Case Message
    The browser declined (e.g. Chrome for a site with little engagement) The browser may clear saved data to free up space
    Safari in a tab Safari deletes a site's data after 7 days of use without visiting it
    No Storage API This browser may clear saved data

    Safari counts as at risk even when it grants persistence, since Apple documents no exemption from the 7-day deletion except for Home Screen and Dock web apps. Those count as protected when granted.

  • Dismissing: remembered in that browser. If the browser clears storage, the notice returns, when it's needed again.

  • Save tooltip: says whether the browser agreed to keep the flow, or repeats the warning.

  • Code:

    • backend/storagePersistence.ts (new) holds the state, requests, and dismissal.
    • MediaLookup.uploadToBrowser requests persistence.
    • App.tsx requests on manual Save and shows the tooltip status and notice.

How browsers decide

Browser persist() Protects against
Chrome, Edge Silent, by engagement, bookmarks, installs, notification permission Clearing under storage pressure
Firefox Permission prompt Clearing under storage pressure
Safari 17+ Silent, mostly Home Screen and Dock web apps Clearing under storage pressure; the 7-day deletion isn't documented

Sources: MDN: Storage quotas and eviction criteria, web.dev: Persistent storage, WebKit: Updates to Storage Policy, WebKit: Full Third-Party Cookie Blocking and More

Limits

  • Autosave alone doesn't trigger a request. Someone who runs prompts but never clicks Save or adds a file isn't asked and sees no notice.
  • No guarantee: browsers can still decline, and Safari in a tab is always at risk. Exporting or running locally remain the only reliable protection; the notice points to both.

Testing

  • Unit tests: storagePersistence.test.ts, 13 tests:
    • granted, declined, already persisted, unsupported, errors;
    • one request per session, including overlapping saves;
    • Safari in a tab vs. a Home Screen app;
    • checking never calls persist(), and doesn't override a request;
    • listeners;
    • dismissal, including blocked storage.
  • Automated: all 1,013 Jest tests pass, tsc is clean, ESLint has no errors, and the build compiles.
  • In the browser (Chromium, browser-only mode via a non-localhost address):
    • No notice before saving.
    • Clicking Save: Chrome declined, and the notice appeared with Export flow and Dismiss, in dark and light mode.
    • The Save tooltip showed the warning.
    • Dismiss, then reload and Save: the notice stayed hidden.
  • Not tested: Firefox's prompt and Safari in real browsers (unit tests only); clicking Export flow, which calls the same function as the toolbar's Export button.

🤖 Generated with Claude Code

Without a local server, flows and responses live in localStorage and
files in IndexedDB, which browsers may clear to free up space. Safari
also deletes a site's script-written data after 7 days of use without
visiting it.

Request persistent storage (navigator.storage.persist()) the first time
work is saved in a session: a manual Save, or a file uploaded or
generated into the browser. Never on page load, since Firefox prompts.
When storage isn't protected (declined, unsupported, or Safari outside a
Home Screen or Dock web app), show a dismissible notice with an Export
button, and say so in the Save button's tooltip. Local installs are
unaffected; they save to disk.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ianarawjo
ianarawjo merged commit d2ad27a into main Sep 16, 2026
21 checks passed
@ianarawjo
ianarawjo deleted the claude/browser-storage-persistence branch September 16, 2026 04:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant