This episode covers storing data on the browser side: localStorage for persistent data, sessionStorage for per-tab data, and cookies for data sent to the server. You learn JSON serialization, safe state patterns, and when to use each mechanism.

When a user closes a tab and opens it again, an application usually loses all context. Web Storage, cookies, and other mechanisms give you a way to store state on the browser side — so preferences, shopping carts, and settings survive into the next visit.
Episode 18 covers the three main client-side storage mechanisms: localStorage, which persists until manually deleted; sessionStorage, which lives for one tab; and cookies, which are automatically sent to the server with every request. You'll also learn safe patterns: JSON serialization, handling corrupt data, and limiting what's allowed to be stored. The key concept: these three mechanisms serve different needs — choosing the wrong one, for example storing a secret token in localStorage, is a serious security mistake.
localStorage stores string key-value pairs and survives even when the browser is closed:
localStorage.setItem("tema", "gelap");
localStorage.setItem("kota", "Jakarta");
console.log(localStorage.getItem("tema"));
console.log(localStorage.getItem("tidak-ada"));
localStorage.removeItem("tema");localStorage.setItem("tema", "gelap") stores a value, getItem reads it, and removeItem deletes it. getItem for a non-existent key returns null. All values are stored as strings — the number 42 will come back as "42". Capacity is about 5 MB per origin.
Because only strings can be stored, objects must be serialized with JSON.stringify and parsed back with JSON.parse:
const preferensi = {
tema: "gelap",
ukuranFont: 16,
bahasa: "id",
};
localStorage.setItem("preferensi", JSON.stringify(preferensi));
const tersimpan = localStorage.getItem("preferensi");
const objek = JSON.parse(tersimpan);
console.log(objek.tema);
console.log(objek.ukuranFont);JSON.stringify(preferensi) converts the object into a JSON string before storing, and JSON.parse turns it back into an object. The setItem with stringify and getItem with parse pattern is the standard for object-based state in localStorage.
JSON.parse throws an error if the string isn't valid JSON — for example because of an older app version. Always wrap it in try...catch:
function bacaPreferensi() {
const mentah = localStorage.getItem("preferensi");
if (mentah === null) return {};
try {
return JSON.parse(mentah);
} catch {
return {};
}
}
const preferensi = bacaPreferensi();
console.log(preferensi.tema ?? "default");try {...} catch returns an empty object if the data is corrupt, so the application doesn't crash when reading old state. The if (mentah === null) handles keys that never existed. This safe parse pattern is mandatory for applications that store state and may change formats between versions.
sessionStorage has an API identical to localStorage, but its scope differs: data lives while the tab is open and disappears when the tab closes. Each tab has its own sessionStorage:
sessionStorage.setItem("posisiScroll", "850");
sessionStorage.setItem("keranjang", JSON.stringify([1, 2, 3]));
console.log(sessionStorage.getItem("posisiScroll"));
const keranjang = JSON.parse(sessionStorage.getItem("keranjang"));
console.log(keranjang.length);sessionStorage.setItem("posisiScroll", "850") stores transient state for the active tab — fitting for scroll positions restored on back-navigation, form drafts, or multi-step wizard state that isn't saved yet. If the data must survive across visits, use localStorage; if it's enough for the active tab, sessionStorage is safer because it's cleaned up automatically.
Unlike Web Storage, cookies are automatically sent to the server on every HTTP request. Access them from JavaScript via document.cookie:
document.cookie = "bahasa=id; max-age=86400; path=/";
document.cookie = "sesi=abc123; path=/; HttpOnly";
console.log(document.cookie);document.cookie = "bahasa=id; max-age=86400; path=/" sets a cookie valid for one day. The path=/ attribute makes the cookie apply to the whole site. HttpOnly marks a cookie unreadable by JavaScript — which is why an HttpOnly session cookie doesn't appear in the document.cookie output.
Cookies have important rules you must understand:
document.cookie =
"token=abc123; max-age=3600; path=/; Secure; SameSite=Strict";Secure; SameSite=Strict restricts the cookie to HTTPS connections and prevents it from being sent from other sites — a basic defense against CSRF attacks. These cookie security attributes are a defense line that shouldn't be loosened without strong reason.
Three mechanisms serve three different needs. The choice in short:
The most important security rule: don't store access tokens in localStorage. localStorage can be read by any script running on the page, and exposing it to an XSS attack means handing over that token. Tokens should live in an HttpOnly cookie that JavaScript can't reach.
A recommended practice: write small functions that hide the serialization details:
const state = {
simpan(nama, nilai) {
localStorage.setItem(nama, JSON.stringify(nilai));
},
baca(nama) {
const mentah = localStorage.getItem(nama);
if (mentah === null) return null;
try {
return JSON.parse(mentah);
} catch {
return null;
}
},
hapus(nama) {
localStorage.removeItem(nama);
},
};
state.simpan("pengguna", { nama: "Arman" });
console.log(state.baca("pengguna"));state.simpan(nama, nilai) and state.baca(nama) hide stringify and parse plus error handling in one place. All callers just use state without knowing the storage details. Patterns like this keep things consistent and make migration easier if the storage mechanism changes.
Episode 18 equipped you with client-side state storage: localStorage for persistent data with JSON serialization, sessionStorage for temporary per-tab data, and cookies for data sent to the server with security attributes. You also learned safe, centralized storage patterns.
Key takeaways:
JSON.parse in try...catch for data that could be corrupt.HttpOnly cookie.In the next episode 19 we'll cover debugging and console tools — finding and fixing bugs with the Console API, breakpoints, and DevTools. You learn to read errors and stack traces, use debugger, and analyze performance with tools already in the browser.