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
.
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.Feature detection now requires you to attempt a write and catch the exception. ↩