113

I know there has been many questions about checking for localStorage but what if someone manually shuts it off in their browser? Here's the code I'm using to check:

localStorage.setItem('mod', 'mod');
if (localStorage.getItem('mod') != null){
  alert ('yes');
  localStorage.removeItem('mod');
} else {
  alert ('no');
}

Simple function and it works. But if I go into my Chrome settings and choose the option "Don't Save Data" (I don't remember exactly what it's called), when I try to run this function I get nothing but Uncaught Error: SecurityError: DOM Exception 18. So is there a way to check if the person has it turned off completely?

UPDATE: This is the second function I tried and I still get no response (alert).

try {
  localStorage.setItem('name', 'Hello World!');
} catch (e) {
  if (e == QUOTA_EXCEEDED_ERR) {
   alert('Quota exceeded!');
  }
}
Bill Keller
  • 793
  • 7
  • 22
user2025469
  • 1,531
  • 2
  • 14
  • 26
  • still doesn't provide any way to see if it's working or not... – user2025469 May 07 '13 at 20:21
  • 7
    Uhhhhmmm. If it throws an exception you *know* it isn't working – PeeHaa May 07 '13 at 20:23
  • 2
    possible duplicate of [How to detect if browser supports HTML5 Local Storage](http://stackoverflow.com/questions/11214404/how-to-detect-if-browser-supports-html5-local-storage) – T J Oct 08 '14 at 17:15
  • 2
    Possible duplicate of [Check for HTML 5 localStorage](https://stackoverflow.com/questions/9535530/check-for-html-5-localstorage) – BuZZ-dEE Nov 02 '17 at 13:17

12 Answers12

171

Use modernizr's approach:

function isLocalStorageAvailable(){
    var test = 'test';
    try {
        localStorage.setItem(test, test);
        localStorage.removeItem(test);
        return true;
    } catch(e) {
        return false;
    }
}

if(isLocalStorageAvailable()){
    // available
}else{
    // unavailable
}

It's not as concise as other methods but that's because it's designed to maximise compatibility.

The original source: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js

Working example: http://jsfiddle.net/6sm54/2/

Joe
  • 15,205
  • 8
  • 49
  • 56
  • 2
    Hey Joe, I get this error when running your function (LS turned on or off) "Uncaught SyntaxError: Illegal return statement" – user2025469 May 07 '13 at 20:18
  • 1
    @user2025469 This code was intended to be used as a function. – Kiruse May 07 '13 at 20:19
  • 1
    Sorry, I should have mentioned that. I've updated my answer and added a demo so you can see it works properly. – Joe May 07 '13 at 20:27
  • 1
    Joe, that's exactly what I've been looking for. When I turn of LS, it alerts unavailable. Is this just a basic javascript function or do I need to include the modernizr JS in my script> – user2025469 May 07 '13 at 20:30
  • It's just plain javascript, no need to include modernizr. – Joe May 07 '13 at 20:33
  • 13
    BEWARE! This Modernizr approach will return false if the localStorage quota is reached. If you have functions dealing with localStorage cleaning, you should edit the catch statement to launch appropriate cleaning actions if the exception name ``e.name ==== 'QUOTA_EXCEEDED_ERR'`` (Chrome) or ``'NS_ERROR_DOM_QUOTA_REACHED'`` (Firefox/Safari) or if ``localStorage.remainingSpace === 0`` in IE. – KrisWebDev Feb 23 '14 at 12:29
  • 1
    @KrisWebDev In Safari incognito locaStorage is blocked and e.name === "QUOTA_EXCEEDED_ERR". I don't know why they did that. But this should still be an indication of localStorage unavailable rather than full. – ColBeseder Jun 26 '16 at 12:10
  • 1
    Do I have to check every time I need to access the local storage or checking only when bootstraping the app is good enough? – Viny Machado Mar 17 '21 at 21:35
32

I'd check that localStorage is defined prior to any action that depends on it:

if (typeof localStorage !== 'undefined') {
    var x = localStorage.getItem('mod');
} else {
    // localStorage not defined
}

UPDATE:

If you need to validate that the feature is there and that it is also not turned off, you have to use a safer approach. To be perfectly safe:

if (typeof localStorage !== 'undefined') {
    try {
        localStorage.setItem('feature_test', 'yes');
        if (localStorage.getItem('feature_test') === 'yes') {
            localStorage.removeItem('feature_test');
            // localStorage is enabled
        } else {
            // localStorage is disabled
        }
    } catch(e) {
        // localStorage is disabled
    }
} else {
    // localStorage is not available
}
Frederik.L
  • 5,522
  • 2
  • 29
  • 41
  • 1
    Under the given circumstances, this is just a feature that will prevent other browsers from erroring... so this doesn't really answer the question. If turned off, `localStorage` still is defined in `window`. – Kiruse May 07 '13 at 20:17
  • 1
    You still get a DOM error...I just can't believe there is no way to check if it's turned off completely... – user2025469 May 07 '13 at 20:21
  • 2
    This isn't a safe approach for Chrome and Opera... likely not Safari either because `localStorage` is completely inaccessible and an exception will be thrown. – Shikkediel Dec 08 '16 at 17:06
  • You don't need all those `else`s... Just a single try catch should do. I see you are testing that the result is actually `'yes'`, but I no of no use case in which that is actually necessary. – Stijn de Witt Jan 23 '17 at 18:44
  • What if something/one else has set a value 'feature_test' - you just blew that away? – Max Waterman Sep 09 '22 at 10:08
23

Feature-detecting local storage is tricky. You need to actually reach into it. The reason for this is that Safari has chosen to offer a functional localStorage object when in private mode, but with it's quotum set to zero. This means that although all simple feature detects will pass, any calls to localStorage.setItem will throw an exception.

Mozilla's Developer Network entry on the Web Storage API's has a dedicated section on feature detecting local storage. Here is the method recommended on that page:

function storageAvailable(type) {
    try {
        var storage = window[type],
            x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return false;
    }
}

And here is how you would use it:

if (storageAvailable('localStorage')) {
    // Yippee! We can use localStorage awesomeness
}
else {
    // Too bad, no localStorage for us
}

If you are using NPM, you can grab storage-available using

npm install -S storage-available

then use the function like so:

if (require('storage-available')('localStorage')) {
    // Yippee! We can use localStorage awesomeness
}

Disclaimer: Both the documentation section on MDN and the NPM package were authored by me.

Stijn de Witt
  • 40,192
  • 13
  • 79
  • 80
  • I'm not sure why you'd not getItem() first, in case something else has used that value (and then set it back after) - unlikely, but possible. – Max Waterman Sep 09 '22 at 10:11
  • Yes, that would make it even more robust. In this code I make it highly unlikely a collission would occur by choosing a unique name, but you are right it might happen. You can consider making a PR for the NPM package – Stijn de Witt Sep 12 '22 at 11:41
  • Actually, we might completely reconsider the approach of doing a feature-detect in the first place. These days I wrapp *all* my calls to localStorage in try..catch and completely omit the feature detect. Because the storage might become full at any moment. I now treat is as file i/o... just like disk might be full at any moment. – Stijn de Witt Sep 12 '22 at 11:43
  • Try catch is, imo, the better approach. In some (admittedly unusual) environments there is no localstorage and attempting to access it causes an exception. – Max Waterman Sep 13 '22 at 12:15
11

MDN updated the storage detect function. In 2018, it's more reliable:

function storageAvailable() {
    try {
        var storage = window['localStorage'],
            x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return e instanceof DOMException && (
            // everything except Firefox
            e.code === 22 ||
            // Firefox
            e.code === 1014 ||
            // test name field too, because code might not be present
            // everything except Firefox
            e.name === 'QuotaExceededError' ||
            // Firefox
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
            // acknowledge QuotaExceededError only if there's something already stored
            storage && storage.length !== 0;
    }
}

Browsers that support localStorage will have a property on the window object named localStorage. However, for various reasons, just asserting that property exists may throw exceptions. If it does exist, that is still no guarantee that localStorage is actually available, as various browsers offer settings that disable localStorage. So a browser may support localStorage, but not make it available to the scripts on the page. One example of that is Safari, which in Private Browsing mode gives us an empty localStorage object with a quota of zero, effectively making it unusable. However, we might still get a legitimate QuotaExceededError, which only means that we've used up all available storage space, but storage is actually available. Our feature detect should take these scenarios into account.

See here for a brief history of feature-detecting localStorage.

mcmimik
  • 1,389
  • 15
  • 32
  • This isn't the exact behavior I'm seeing in Safari with iOS 12.1. I'm able to set things and retrieve them - they just don't persist after I close that tab. Even if I visit another website in the same tab and come back my saved data is still there. So not sure how old this comment is. – Simon_Weaver Apr 02 '19 at 19:39
  • 1
    Apparently it was a bug that was since fixed - https://stackoverflow.com/questions/14555347/html5-localstorage-error-with-safari-quota-exceeded-err-dom-exception-22-an. Have to assume if your users are in private mode they expect to lose 'session' when they go away and come back. – Simon_Weaver Apr 02 '19 at 19:41
  • `This isn't the exact behavior I'm seeing in Safari with iOS 12.1. I'm able to set things and retrieve them - they just don't persist after I close that tab.` Yeah. Thankfully, the WebKit developers got smart and changed the broken behavior. In old versions, they throw quota exceeded errors an any attempts to write to localStorage when in private mode. This is unexpected and caused a lot of issues for developers. In later versions they changed it to match the behavior of other browsers and cookies: it will work but only for as long as the browser remains open. – Stijn de Witt Aug 27 '20 at 07:41
  • I'm not getting any error when trying to write or read from local storage while using Safari private mode on mobile. Safari will simply do nothing and fail silently. – SomewhereDave Oct 26 '20 at 11:39
  • 1
    The 'failing silently' is actually the expected behavior in private/incognito mode. Your code works, but the stuff you stored gets erased when the window is closed. This is exactly the same behavior as for cookies. When a user chooser private/incognito mode, they want to leave no traces when they close the window. I would not worry about it. It's the user that made this choice and there simply is no way (unless the browser has a bug) to store stuff on the user's device in private mode. That's a feature. – Stijn de Witt Sep 12 '22 at 11:49
4

With this function you can check if localstorage is available or not, and you keep under control the possible exceptions.

function isLocalStorageAvailable() {

    try {
        var valueToStore = 'test';
        var mykey = 'key';
        localStorage.setItem(mykey, valueToStore);
        var recoveredValue = localStorage.getItem(mykey);
        localStorage.removeItem(mykey);

        return recoveredValue === valueToStore;
    } catch(e) {
        return false;
    }
}
luis moyano
  • 100
  • 4
0

It is better to check availability of localStorage in conjunction with cookies, because if cookie is enabled the browser could detect that localStorage is available and type it as object, but provide no possibility to work with it. You use the next function to detect both localStorage and cookies:

const isLocalStorage = () => {
  try {
    if (typeof localStorage === 'object' && navigator.cookieEnabled) return true
    else return false
  } catch (e) {
    return false
  }
}
Ruslan Korkin
  • 3,973
  • 1
  • 27
  • 23
  • 1
    As explained in another answer, it was a Safari bug that set localStorage to an empty object when private browsing. Browsers should not be doing this. Cookies and localStorage are completely different mechanisms. – Phil Jun 01 '21 at 09:32
  • 1
    This is not Safari bug. You can check it in Chrome, disable cookies and try again – Ruslan Korkin Dec 03 '21 at 12:49
0

You can try this method Anytime validate the content of the localstore

const name = localStorage.getItem('name');
if(name){
    console.log('Exists');
}else
{
    console.log('Not found');
}
0

I tried this solution in Chrome, Firefox and Edge and it worked correctly.

if (localStorage.getItem('itemName') === null )
{
    // your code here ...
}

if the local variable on localStorage do not exist it will brind false.

0

You can create a checker function which tries to get a non existing item from the localStorage. When the localStorage is turned on you will normally get null returned. But when the localStorage is turned off an error will be thrown. You don't have to set any item for the checking.

const checkLocalStorage = () => {
    try {
      localStorage.getItem("x");
      return true;
    } catch {
      return false;
    }
}
Gipfeli
  • 197
  • 3
  • 8
-1

Modifying Joe's answer to add a getter makes it easier to use. With the below you simply say: if(ls)...

Object.defineProperty(this, "ls", {
  get: function () { 
    var test = 'test';
    try {
      localStorage.setItem(test, test);
      localStorage.removeItem(test);
      return true;
    } catch(e) {
      return false;
    }
  }
});
Ronnie Royston
  • 16,778
  • 6
  • 77
  • 91
  • Why the downvote? It works, and typing `ls` is better than typing `lsTest() === true`. ...? – Ronnie Royston Jan 04 '17 at 16:12
  • It does not work. You are assigning an object to `ls`... as such `if (ls)` will always evaluate to `true`. Just check it by changing your `get` method to read `get: function(){return false}` and you will see. Also, typing `ls` is not better.... This test is going to not be too often in your code (if you write it in a smart way), so why pollute the (global) scope with a very short variable? – Stijn de Witt Jan 23 '17 at 18:33
  • your right. I'm gonna have to fix that... Thank you! – Ronnie Royston Jan 23 '17 at 18:52
  • @StijndeWitt it works now. Thanks for your feedback... In terms of polluting the global scope, I see your point but I think that's an opinion. Somebody might find that typing `if(ls){...` is worth it. – Ronnie Royston Jan 23 '17 at 20:23
  • ` === true` is not needed any more for checking a function result than a getter result. Typing `lsTest()` is better than `ls` because it's more descriptive, and `isLocalStorageAvailable()` would be even better. It's best to avoid getters, because they can be *surprising* because there's no indication that it will execute code when typing (e.g.) `ls`. There's no reason to use a getter here. If you really don't want the parentheses, you could just compute the availability once and store the result in a global variable. Then it's simpler to think about (no hidden execution) *and* shorter overall. – 1j01 Dec 10 '21 at 20:30
-2

Here is an easy check:

if(typeof localStorage === 'undefined'){

Brady
  • 733
  • 1
  • 6
  • 16
  • 5
    The type of `localStorage` returns `object`, even if it is disabled in Firefox or IE. In Chrome and Opera `typeof` throws an exception and breaks the whole script when the user has turned it off... – Shikkediel Dec 08 '16 at 03:29
  • And in Safari in Private Browsing mode, you get a working `localStorage` object that has a quota of zero and thus throws an exception whenever you try to write to it. Which is why the local storage feature detecting code now always tries to write an item. – Stijn de Witt Jan 23 '17 at 18:42
-3

Use this to check localStorage is set or not. Its help you to get status of Localstorage.

    if( window.localStorage.fullName !== undefined){

           //action
   }else{
          }
Lucky W
  • 50
  • 1
  • 7
  • 4
    You don't need to wait for the document to be loaded to access localStorage (so `$()` is pointless) More importantly, this code will throw an error if localStorage is unavailable. – 1j01 Mar 08 '14 at 14:38
  • Actually, Mozilla docs state that `localStorage` is synchronous in nature so it can block rendering of the main document. Waiting for it to be ready would therefore be a good approach. – Shikkediel Dec 08 '16 at 17:35
  • What they mean by saying that `localStorage` is synchronous is that `localStorage.getItem('someKey')` actually immediately returns the item. It does not accept a callback function or return a `Promise`, it just returns the data right away. Contrast that to e.g. `var result = fetch('https://example.com/data.json')`... that returns a `Promise`, which makes it async. You'll have to call the `then` method to get at the data (will only happen during the next tick): `result.then(function(data){ /* only here do we get the data */ })` – Stijn de Witt Jan 23 '17 at 18:40
  • It's about the fact that synchronous calls block rendering, interrupting further parsing of the page. Callback behaviour is rather irrelevant here. – Shikkediel Jan 30 '17 at 08:37