Per-account browser storage

Everything the app stores in the browser is silently prefixed with the account's subdomain, so any legacy entry from another account becomes unreadable.

What it is

A tiny script injected into the page head that wraps the browser's storage getter, setter and remover so every key is prefixed with the current subdomain. It runs synchronously before the app hydrates, so all subsequent application code is prefixed automatically without any call site knowing about it.

Also called: localStorage prefix · leftover data on a subdomain · browser storage scoping

See it
Per-account browser storage
Area
Platform & Admin
Group
Tenancy & isolation
System
Multi-Tenancy & Identity
Solves
2 named problems
01The script derives the subdomain from the hostname, skipping localhost, bare IPs and reserved labels.
02getItem, setItem and removeItem are redefined to prepend '<subdomain>::' to every key.
03The property descriptors are marked configurable and writable, which is required so development tooling that proxies the storage object doesn't throw.
Browser devtools Application panel showing keys prefixed 'acme::' alongside untouched auth keys. Injected by SCOPED_LS_SHIM in src/app/layout.tsx. Sample data — no customer information appears here.
How it works
  1. 1The script derives the subdomain from the hostname, skipping localhost, bare IPs and reserved labels.
  2. 2getItem, setItem and removeItem are redefined to prepend '<subdomain>::' to every key.
  3. 3The property descriptors are marked configurable and writable, which is required so development tooling that proxies the storage object doesn't throw.
  4. 4The apex is intentionally left unprefixed so the original account's existing preferences survive untouched.
  5. 5It installs once per page and marks itself so it can't double-wrap.
Why we built it

The comment is unusually candid that this is a belt over an already-working brace: 'localStorage is already per-origin in browsers, so cross-tenant bleed is structurally impossible. But during development we hit a window where server bugs wrote one tenant's data into another tenant's own localStorage… Even after fixing the server, that stale data persisted in the visited subdomain's localStorage.' Prefixing orphans those entries rather than requiring a cleanup migration. The descriptor detail is a real bug too: a plain value descriptor is non-configurable, 'which violates a JS Proxy invariant… once dev tooling wraps window.localStorage in a Proxy — any later localStorage.getItem read then throws on tenant subdomains.'

The problem
  • Historic bad data written into a subdomain's storage outlived the server-side fix.
  • A cleanup would otherwise require asking every user to clear site data.
Sound familiar?
What you get
Legacy stored entries from a previous state become invisible without a cleanup step.
Every storage read and write is account-scoped without call sites needing to know.
The original account's long-standing preferences are preserved.

See it on your own jobs

Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.

or keep browsing features →