Browser storage can preserve small interface preferences and draft text across page visits. It is not a secure vault: scripts running in the page's origin can read localStorage, users can edit it, and storage can be unavailable or cleared. A server should never use a value retrieved from localStorage as proof of identity or permission. The code below stores a display density choice with an explicit allowlist and a versioned key. Reading the value is wrapped in a try block because access and parsing can fail. Sensitive session credentials belong in a different design with server-side controls; a theme preference does not.
Browser storage: save convenience data without storing credentials
Case study
An analyst chooses compact rows for an inspection queue. The page writes 'compact' under a versioned preference key and restores it on the next visit. If storage is blocked, the queue stays readable using the default comfortable layout. If an attacker or old script writes an unknown string, the allowlist rejects it. A different browser profile will not inherit the choice, which is acceptable for a display preference but would be unacceptable for a shared workflow state. Draft submissions that matter should be saved with a server contract, conflict rules, and an explicit retention policy.
Working contract
const preferenceKey = "inspection-density-v2";
const allowedDensity = new Set(["compact", "comfortable"]);
function readDensity() {
try {
const saved = localStorage.getItem(preferenceKey);
return allowedDensity.has(saved) ? saved : "comfortable";
} catch {
return "comfortable";
}
}
function saveDensity(selection) {
if (!allowedDensity.has(selection)) return false;
try {
localStorage.setItem(preferenceKey, selection);
return true;
} catch {
return false;
}
}Cost and tradeoffs
A single preference read and write are small synchronous operations, but localStorage can block the main thread and should not hold large documents. The allowlist check is O(1); reading a value of length L and copying it is O(L). Storage quota, eviction, and private mode behavior vary, so failure must leave the interface usable. If a value must be shared among devices or audited, server storage is the appropriate authority. A storage event can notify other tabs, but it does not turn local data into trusted state.
Common Mistakes
- Do not store passwords or bearer tokens beside interface preferences.
- Do not assume localStorage always exists or accepts writes.
- Do not trust a restored value without checking its allowed shape.
- Do not treat one browser profile as the source of truth for team data.
Continue through the stack
Sessions and CSRF: keep identity on the server; HTTP caching: validate a changed representation with an ETag; JavaScript Tutorial.
Broader connections
IndexedDB for Local Drafts; Offline Sync and Conflict Policy.
Failure trace
A page stores the latest case note and bearer token beside a theme preference in localStorage. A script injected through an unrelated widget reads both, and a shared browser later reveals the old note to another person. Keep only low-risk convenience state in browser storage, validate its shape on read, and let the server hold authoritative records and session state.
Verification
- Seed an unexpected stored value and confirm the page falls back without crashing.
- Block storage writes and verify the control remains usable for the current visit.
- Sign out and confirm account-bound local data is removed or becomes inaccessible by policy.
Decision note
Storage APIs are synchronous or quota-bound in ways that vary by browser. Treat them as convenience caches and drafts with explicit loss and privacy rules, not as an invisible database.
