How Safari Handles navigator.storage.persist() Requests
This article provides an overview of how the
navigator.storage.persist() API functions within the Safari
web browser to protect local web application data from automatic
deletion. It covers Safari's default storage eviction policies, the
specific criteria WebKit uses to grant persistent storage, and how
developers can implement this API to secure data against Intelligent
Tracking Prevention (ITP) and low-disk-space purges.
Understanding Safari's Default Storage Eviction
By default, Safari treats all website data—such as IndexedDB, Cache API, and LocalStorage—as "best-effort." This means the browser can automatically delete this data without warning under two specific conditions:
- Intelligent Tracking Prevention (ITP): Safari enforces a strict 7-day cap on all script-writable storage. If a user does not interact with a website for seven days, Safari automatically purges that origin's storage to prevent cross-site tracking.
- Storage Pressure: If the user's device runs low on disk space, Safari will evict data from origins that have not been used recently to free up capacity.
To prevent this automatic deletion, web applications must request an exemption using the Storage Standard API.
How the Exemption Request Works
When a web application calls
navigator.storage.persist(), it asks Safari to change the
origin's storage bucket mode from "best-effort" to "persistent." The
method returns a JavaScript Promise that resolves to a boolean value:
true if the exemption is granted, and false if
it is denied.
Unlike some browsers that display a permission prompt to the user when this API is called, Safari evaluates the request silently in the background. WebKit uses internal heuristics to decide whether the origin deserves persistent storage.
Safari will generally grant the exemption and return
true if the website meets at least one of the following
criteria:
- Home Screen Installation: The user has added the web application to their Home Screen on iOS or iPadOS, or to the Dock on macOS (functioning as a Progressive Web App).
- Notification Permissions: The user has explicitly granted the origin permission to send Web Push Notifications.
- User Engagement: The user interacts with the site frequently, has bookmarked it, or uses it heavily over a sustained period.
If none of these conditions are met, Safari will silently deny the
request and resolve the Promise to false.
What Happens When Exemption is Granted
Once navigator.storage.persist() resolves to
true, Safari alters how it manages that specific origin's
data:
- ITP Exemption: The 7-day inactivity timer is disabled for that origin. Data stored in IndexedDB and the Cache API will remain intact even if the user does not visit the site for weeks or months.
- Disk Pressure Protection: If the device runs low on physical storage, Safari will delete data from all "best-effort" origins first. Persistent origins are exempt from automatic disk-space eviction unless all non-persistent data has been purged and the device is still critically low on space.
Note that persistent storage does not protect data from manual deletion. The user can still clear the data at any time through Safari’s settings or by clearing their browsing history.
Implementing the API
To request an exemption from automatic eviction in Safari, developers
should first check if the storage is already persistent using
navigator.storage.persisted(), and then request persistence
if it is not.
async function requestStoragePersistence() {
// Check if the Storage API is supported in the current browser
if (navigator.storage && navigator.storage.persist) {
// Check if storage is already persistent
const isPersisted = await navigator.storage.persisted();
if (isPersisted) {
console.log("Storage is already exempt from automatic eviction.");
return true;
}
// Request exemption from automatic eviction
const granted = await navigator.storage.persist();
if (granted) {
console.log("Storage persistence granted by Safari.");
return true;
} else {
console.log("Storage persistence denied. Data remains best-effort.");
return false;
}
}
return false;
}Because Safari relies on user actions (like enabling notifications or
installing the web app) to grant persistence, developers should call
navigator.storage.persist() immediately after these actions
occur, rather than on the initial page load.