LessonLesson 29 of 34

Guest progress, local storage, and honest persistence

Store small guest preferences safely, handle unavailable storage and invalid data, and distinguish device state from account synchronization.

Advanced5 min readLearn · Practice · Review

Published by HTML Code Runner · AI-assisted material · Independent editorial review pending · Editorial policy

On this page

Learning objectives

Use localStorage defensively; serialize a versioned record; explain the limits of browser-only progress and avoid sensitive storage.

Prerequisites

Understand JavaScript objects, JSON, try/catch, and same-origin boundaries.

Choose the right persistence promise

Local storage stores string values for an origin and commonly survives page reloads and browser restarts. Session storage is scoped to a page session and is useful for shorter-lived state. Neither automatically synchronizes with a WordPress account or another device. A site should describe guest progress as saved on this browser rather than implying a durable cloud backup.

Storage can be unavailable, full, cleared by the user, or affected by private-browsing and browser policies. A successful setItem call today does not mean the value will exist forever. Design the task so a failed save does not break the page, and provide a clear way to reset locally stored preferences.

Treat stored values as untrusted input

Web Storage stores strings, so structured data usually passes through JSON.stringify and JSON.parse. Parsing can fail if old code, an extension, or a user modifies the stored value. Wrap access and parsing in error handling, then validate the resulting shape before using it. A valid JSON array is not automatically the object your code expects.

Version your records when their shape may evolve. For example, a progress record can contain version, completed lesson identifiers, and updatedAt. Stable lesson identifiers are better than a page’s current title because titles can change. Keep migrations small and explicit; a broken migration should fall back to a usable empty state rather than prevent the lesson from loading.

Do not store passwords, session secrets, or sensitive personal notes in localStorage as a shortcut. Scripts running in the origin can access it, and an XSS flaw can expose its contents. Browser storage is a convenience for appropriate local state, not a confidential vault.

Keep the UI truthful across tabs and failures

The storage event can notify other same-origin documents when a storage area changes, but it is not fired on the exact document that made the change. Update the current UI directly after a successful operation. If several tabs write a whole progress object independently, a later write can overwrite newer values from another tab; consider merging state or using a more suitable persistence design.

Web Storage operations are synchronous, so avoid large data and frequent writes in tight input loops. IndexedDB is a different asynchronous database API for more complex local data, with its own design and error-handling requirements. A simple completion checkbox usually needs only a small versioned record.

Working example

<button type="button" id="save-progress">Save this lesson locally</button>
<button type="button" id="clear-progress">Clear this sample</button>
<p id="storage-status" role="status">No change has been made.</p>

Another example

<script>
function readProgress() {
  try {
    const value = JSON.parse(localStorage.getItem("demo-progress") || "null");
    return value && value.version === 1 && Array.isArray(value.completed) ? value : { version: 1, completed: [] };
  } catch {
    return { version: 1, completed: [] };
  }
}
</script>

Expected output

On a normal same-origin page, Save writes a small sample record and Clear removes it. In the isolated playground, opaque-origin storage may be unavailable; the example catches that condition and displays an explanation instead of throwing an uncaught exception.

Common mistakes

Do not show Saved before checking whether the write succeeded. Do not assume parsed JSON has the expected type. Do not erase all of localStorage with clear when you only own one feature key. Do not advertise device-local progress as account synchronization.

Accessibility and browser notes

Announce the result without moving focus away from the action. Keep clear/reset actions explicit about what they remove. A learner using a shared device should understand that another person using the same browser profile may see local progress.

Practice

Write a safe removal operation for only the key demo-progress, with success and failure feedback.

Review the solution and reasoning
try {
  localStorage.removeItem("demo-progress");
  status.textContent = "This sample’s local progress was cleared.";
} catch {
  status.textContent = "Storage is unavailable; no change could be confirmed.";
}

Removing one owned key avoids deleting unrelated application state. The error message avoids claiming a change that could not be confirmed. In production, pair local data controls with an accurate privacy explanation.

Related lessons

Specifications and further reading

One more skill in your toolkit.

Finished the explanation and exercise? Save your progress.