Storage

How to Inspect Local Storage, Session Storage and Cookies in Chrome

Find, read, edit and clear client-side storage in Chrome, understand which mechanism to use for what, and debug the state bugs they cause.

10 min read

Open DevTools (F12) and go to the Application tab. In the left sidebar under Storage you'll find Local Storage, Session Storage, IndexedDB, Cookies and Cache Storage. Expand any of them, pick your origin, and you get an editable key/value table.

Double-click any value to edit it. Press Delete to remove a row. The refresh icon re-reads the store, which matters because the table doesn't update live when the page writes to it.

Which storage does what

CapacityLifetimeSent to serverAccess
Cookies~4KB eachUntil expiryYes, every requestJS unless HttpOnly
localStorage~5–10MBUntil clearedNoSynchronous JS
sessionStorage~5–10MBUntil tab closesNoSynchronous JS
IndexedDBLarge, quota-basedUntil clearedNoAsynchronous JS
Cache StorageLarge, quota-basedUntil clearedNoService worker / JS

Two consequences worth internalising. Cookies travel with every single request to the domain, including images and fonts, so a fat cookie is a permanent tax on every page load. And localStorage is synchronous, which means a large read blocks the main thread — a real cause of poor interaction latency on pages that read it in a loop.

Reading and writing from the Console

Sometimes quicker than clicking through the Application panel, especially when you want to see everything at once:

js
// Everything in localStorage, as an object
Object.fromEntries(Object.entries(localStorage));

// Nicely formatted, with JSON values expanded
console.table(
  Object.keys(localStorage).map(k => {
    let v = localStorage.getItem(k);
    try { v = JSON.parse(v); } catch {}
    return { key: k, value: v };
  })
);

// Cookies readable by JavaScript (HttpOnly ones are excluded)
document.cookie.split('; ').map(c => c.split('='));

// How much quota are we actually using?
await navigator.storage.estimate();

That last one is useful when a storage write starts throwing QuotaExceededError and you need to know whether you're near a real limit or hitting a per-origin cap.

Cookies specifically

The Application panel's cookie table has columns you should be reading, not just the name and value:

  • HttpOnly — JavaScript can't read it. Session cookies should have this. If yours doesn't, an XSS becomes a session hijack.
  • Secure — only sent over HTTPS. Should be on for everything.
  • SameSiteLax is the modern default. None requires Secure and is the setting that breaks embedded flows when it's missing.
  • Domain — a leading dot means it's shared with subdomains, which is often broader than intended.
  • Path — narrower scoping than most people use.
  • Expires / Max-Age — blank means a session cookie that dies with the browser.

Cookie problems are usually attribute problems rather than value problems. "It works in Chrome but not in an iframe" is SameSite. "It works on the apex domain but not on www" is Domain. "It vanishes after login" is usually a Path or Secure mismatch between the setting request and the reading one.

Checking those flags one cookie at a time gets old quickly. The Cookie Security Audit in Web Developer Tools reads Secure, HttpOnly and SameSite across every cookie at once and tells you which ones are missing what. There's also Cookie Search for finding a specific one, Add Cookie and Delete Individual Cookies for editing, Export Cookies for capturing a state you want to restore later, and a Third-party Cookie Report listing cookies set by domains other than the one you're on.

Web Developer Tools popup open on the Storage Manager category, showing View & Edit Storage, Clear Local Storage, Clear Session Storage, Add Cookie, Edit Cookies and Storage Usage Summary
Storage Manager covers cookies, localStorage, sessionStorage, IndexedDB and Cache Storage from one place, including per-item deletion.

Debugging state bugs

Most storage bugs are one of four things.

Stale data with a changed shape

You ship a new version, the stored object gains a field, and existing users have the old shape sitting in localStorage. The app reads it and crashes on a property that doesn't exist. This is the most common one, and the fix is versioning:

js
const KEY = 'prefs:v3';

function loadPrefs() {
  try {
    const raw = localStorage.getItem(KEY);
    return raw ? { ...DEFAULTS, ...JSON.parse(raw) } : DEFAULTS;
  } catch {
    localStorage.removeItem(KEY);   // corrupt or old format
    return DEFAULTS;
  }
}
Version the key, spread over defaults, and always wrap the parse.

Writing objects without serialising

localStorage.setItem('user', { name: 'Sam' }) stores the string [object Object]. It fails silently and produces a confusing bug three screens later. Always JSON.stringify going in and JSON.parse coming out, inside a try/catch.

Storage that isn't available

In Safari's private mode, in some embedded webviews, and under strict cookie blocking, accessing localStorage can throw rather than return null. Any code path that assumes it exists will break for those users, and you won't see it locally.

Two tabs disagreeing

localStorage is shared across tabs on the same origin. Two tabs writing the same key will clobber each other. The storage event fires in *other* tabs when a value changes, which is the mechanism for keeping them in sync — and also the reason a logout in one tab can log you out everywhere, if someone wired it that way.

Clearing storage properly

There are several levels, and picking the wrong one is why "I cleared everything" sometimes doesn't help:

  1. 1One key — delete the row in the Application panel, or localStorage.removeItem(key)
  2. 2One store — the clear icon at the top of the table, or localStorage.clear()
  3. 3Everything for this origin — Application → StorageClear site data. This includes service workers and caches.
  4. 4A truly clean slate — an incognito window, or a new browser profile

Step 3 is the one people miss. A service worker will happily serve a cached bundle after you've cleared localStorage, so the app keeps behaving as though nothing changed. If a fix isn't taking effect, unregister the service worker before you start doubting the fix.

WDT has individual clear actions for each store (Clear Local Storage, Clear Session Storage, Clear IndexedDB, Clear Cache Storage) plus Detect Service Workers and Unregister Service Worker, which together cover the "why is the old version still loading" case.

What not to put in client-side storage

Anything readable by JavaScript is readable by any script running on your origin, including a compromised third-party dependency. That rules out:

  • Session tokens and refresh tokens — use HttpOnly cookies
  • Personal data of any kind
  • API keys or secrets, which don't become secret by being minified
  • Anything you'd be uncomfortable seeing in a support screenshot

The counter-argument is that HttpOnly cookies have their own risks, mostly CSRF. That's a real trade-off, but it's a trade-off with mitigations, whereas "an XSS reads the token straight out of localStorage" has none. WDT's Secret Detector scans the page for things that look like API keys, which is worth running once on your own site — the results are occasionally uncomfortable.

Cookie flags are a security topic as much as a storage one, so the security checks guide is the natural follow-on. If you want to be faster in the Application panel generally, the DevTools tips cover the shortcuts worth learning.

Related reading

All 15 articles