GrapesJS/grapesjs · error

localStorage not available

Error message

localStorage not available

What it means

The LocalStorage storage manager checks that `window` and `localStorage` exist (when `checkLocal` is enabled). If storage is unavailable — no browser window, storage disabled/blocked, or restricted environments — `hasLocal(opts, true)` throws 'localStorage not available', causing store/load to fail.

Source

Thrown at packages/core/src/storage_manager/model/LocalStorage.ts:38

    if (this.hasLocal(opts, true)) {
      localStorage.setItem(opts.key!, JSON.stringify(data));
    }
    return data;
  }

  async load(opts: LocalStorageConfig = {}) {
    let result = {};

    if (this.hasLocal(opts, true)) {
      result = JSON.parse(localStorage.getItem(opts.key!) || '{}');
    }

    return result;
  }

  hasLocal(opts: LocalStorageConfig = {}, thr?: boolean) {
    if (opts.checkLocal && (!hasWin() || !localStorage)) {
      if (thr) throw new Error('localStorage not available');
      return false;
    }

    return true;
  }
}

View on GitHub (pinned to 2bdeda85b8)

Solutions

  1. Use a different storage type, e.g. `storageManager: { type: 'remote' }` with proper settings, or disable autosave.
  2. Set `checkLocal: false` in LocalStorage options if you know storage exists or want graceful fallback.
  3. Polyfill/stub localStorage in non-browser or test environments (e.g. node-localstorage, jsdom setup).
  4. Implement a custom storage manager for restricted environments.

Example fix

// before
storageManager: { type: 'local', options: { checkLocal: true } }
// after
storageManager: { type: 'local', options: { checkLocal: false } }
// or polyfill in Node/jsdom:
// global.localStorage = new LocalStorage('./scratch');
Defensive patterns

Strategy: fallback

Validate before calling

function localStorageAvailable() {
  try {
    const k = '__test__';
    window.localStorage.setItem(k, k);
    window.localStorage.removeItem(k);
    return true;
  } catch { return false; }
}
const storageType = localStorageAvailable() ? 'local' : 'remote';

Type guard

function hasLocalStorage(): boolean {
  try { return typeof window !== 'undefined' && !!window.localStorage; } catch { return false; }
}

Try / catch

try {
  await editor.store();
} catch (err) {
  if (err.message === 'localStorage not available') {
    // switch to remote storage or skip persistence
    console.warn('Persistence skipped: localStorage unavailable');
  } else throw err;
}

Prevention

When it happens

Trigger: Using `storageManager: { type: 'local' }` with `checkLocal: true` in an environment without localStorage: SSR/Node, webviews with storage disabled, iframes with blocked third-party storage, Safari private mode in old versions, or `localStorage` shadowed/undefined.

Common situations: Server-side rendering of the editor, loading GrapesJS inside sandboxed iframes, privacy modes or browser settings disabling site data, automated tests in jsdom without localStorage polyfill.


AI-assisted analysis of GrapesJS/grapesjs@2bdeda85b8 (2026-08-30). Data as JSON: /api/errors/cc11fba7d38171b0. Report an issue: GitHub.