Choose and observe storage

Understand origin and site boundaries

Separate origins, sites, tabs, and top-level storage partitions so data does not cross a boundary by accident.

Every storage boundary in the browser starts with the URL. Change one small part of it and you’re looking at a different bucket of data.

This is where a lot of “my data vanished” reports come from. The data is still there. The page is just looking in a different bucket.

The origin

An origin is the combination of scheme, host, and port. All three must match.

These are four different origins:

https://notes.test
http://notes.test
https://app.notes.test
https://notes.test:8443

Web Storage and IndexedDB follow the origin boundary. A value saved on https://notes.test is invisible to http://notes.test. Same host, different scheme, different bucket.

A common way to hit this: you develop on http://localhost:3000, then start a second dev server on port 5173. Your saved notes seem gone. They belong to the other port.

The site

Cookies play by their own rules. They match on domain and path, not on the full origin. A cookie doesn’t care about the port, and it can be shared across subdomains if you ask with the Domain attribute.

Then there’s the site. The SameSite cookie attribute reasons about sites, not origins. A site is roughly the registrable domain: notes.test and app.notes.test are the same site, even though they are different origins.

Three words that look interchangeable and aren’t:

  • origin: scheme + host + port. Used by Web Storage and IndexedDB
  • domain and path: used by cookie matching
  • site: the registrable domain. Used by SameSite

Keep them separate in your head. We’ll need all three in the cookies module.

Partitions for embedded content

One more layer. When your page is embedded inside another site, in an iframe, the browser may give it partitioned storage. The storage key becomes “your origin, as seen inside that top-level site”.

The same widget embedded on two unrelated sites gets two separate buckets. That’s by design, so one identifier can’t follow a user across the web.

The tab boundary

sessionStorage adds a boundary the others don’t have: the top-level tab. Two same-origin tabs share the same localStorage. They normally get separate sessionStorage.

That’s exactly the behavior we want for the editor draft in our field-notes app. A draft belongs to the tab where you’re typing it, not to every open tab.

See it yourself

Take any test page and put one value in localStorage and one in sessionStorage. Then open the same page on HTTP and HTTPS, on a subdomain, on another port, and in a second tab.

Before opening DevTools each time, write down which values you expect to see. Then check the Application panel (Storage in Firefox). Where your prediction was wrong, go back to the three definitions and find which boundary you crossed.

Lesson completed