DOM Exception 22 - Quota Exceeded on Safari Private Browsing with localStorage

ERROR: QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota.”

Safari in Private Browsing on iOS and OSX

So apparently Apple didn’t want to (or for undisclosed technical reasons couldn’t) support the WebStorage standard (known as localStorage and sessionStorage) in Private Browsing mode.

EDIT 2017-10-17: Alexander points out in the comments below that Apple fixed this, and that it should ship in iOS 11

Other browsers fully support the protocols, with the understanding that at the end of the private browsing session the storage will be wiped clean.

As far as I know the feature specification doesn’t define what browsers should do in Private Browsing, so I suppose its not technically a spec violation.

If Apple didn’t want to support it, they should have just not exposed the localStorage or sessionStorage properties on window. Then everybody’s if (window.localStorage) checks would work correctly and we could move on with our lives.1

But instead of doing that, they made it seem like it was available but instead throw an exception when you try to write to it. Reading just returns null, and remove is apparently a no-op. But as soon as you attempt to write, your page explodes. This is probably half way through some process, making it more difficult to diagnose than necessary.

Why expose a broken API?

Frequently Asked Questions

Why did Apple do this?

I don’t know.

Care to speculate?

Sure. It’s probably some difficulty with their technical implementation that made it difficult to clear the storage at the end of the session. They’re already doing that with cookies, so I doubt it was just the confused orders of some middle manager.

How do I reliably feature detect localStorage?

You’ll have to attempt a write and catch the raised exception. It’s not enough to just check the existence of window.localStorage.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function isPrivateBrowsingSupportedEvenIfThisIsSafari() {
if (window.localStorage) {
var test = "__localstoragetest__";
try {
window.localStorage.setItem(test, test);
window.localStorage.removeItem(test);
} catch(ex) {
console.log("No storage for you!");
return false;
}
return true;
}
return false;
}

What if I’m relying on localStorage and need to support private browsing on Safari?

That sounds like trouble. I feel for you.

You need to store that data server-side and retrieve it when needed.

If your data storage needs are small, you can polyfill localStorage with cookies, but in my experience its pretty easy to hit the max cookie size, especially if you’re URL encoding JSON.

Its probably better to treat localStorage as a progressive enhancement: it adds useful extra features but is not a key requirement.

What if I’ve completely architected my app around localStorage and just discovered this in production?

You’ll obviously need to re-architect or tell those creepers to quit using private browsing.

And add Safari Private Browsing to your QA device support matrix.


  1. 1.Feature detection now requires you to attempt a write and catch the exception.