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:

  1. 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.
  2. 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.