Handling Session Expiration Under Safari's Intelligent Tracking Prevention
Safari's Intelligent Tracking Prevention (ITP) can silently cap cookie lifespans to 7 days. Learn how to diagnose these disappearances and use the Storage Access API for session persistence.
30 Sept 2025, 19:07 UTC

The Mystery of the Disappearing Cookie
You have configured your session cookies with a 30-day Max-Age, yet your Safari users are being logged out after exactly seven days. There are no errors in the console, and the server is sending the correct headers. The problem isn't your backend logic; it is Intelligent Tracking Prevention (ITP).
ITP is a privacy feature in Safari (macOS and iOS) that uses on-device machine learning to identify tracking patterns. To prevent long-term cross-site profiling, Safari imposes a strict cap on the expiration of client-side cookies. If a cookie is set via document.cookie (JavaScript), Safari often limits its lifespan to 7 days, regardless of the expiration date you specify. This creates a significant gap between intended session length and actual user experience.
How ITP Distinguishes First-Party from Third-Party
ITP treats cookies differently based on the context in which they are set. A first-party cookie is one set by the domain currently appearing in the browser's address bar. These are generally preserved, provided they aren't flagged as tracking mechanisms.
Third-party cookies—those set by a domain other than the one the user is visiting—are blocked by default. If your architecture relies on a shared authentication domain (e.g., auth.example.com providing cookies for app.example.com), Safari may treat these as third-party depending on the specific configuration and the user's privacy settings. This leads to silent failures where the cookie appears to be set in the developer tools but is purged or ignored during the next request.
Implementing the Storage Access API
When your application legitimately needs access to third-party cookies—such as for a federated login or an embedded payment gateway—you cannot rely on the browser to "just allow it." You must use the Storage Access API to explicitly request permission from the user.
The process requires a user-initiated gesture (like a button click) to trigger the request. You cannot call this API on page load.
Example: Requesting Storage Access
// This must be called inside a user-triggered event handler (e.g., onClick)
async function requestCookieAccess() {
try {
// Check if the document already has access
const hasAccess = await document.hasStorageAccess();
if (hasAccess) {
console.log("Access already granted");
return;
}
// Request access to first-party storage for the third-party domain
await document.requestStorageAccess();
console.log("Access granted by user");
// Now you can read/write the third-party cookies
} catch (err) {
console.error("Storage access denied:", err);
}
}
Verification and Diagnostics
Because ITP operates silently, diagnosing it requires specific steps in the Safari Web Inspector. To verify if ITP is capping your cookies:
- Open Web Inspector > Storage > Cookies.
- Compare the
Expires/Max-Agevalue sent by your server with the actual expiration date recorded by the browser. - If the server sent 30 days but Safari shows 7, ITP is active for that cookie.
To test cross-site flows, use a Private Browsing window. This isolates the session and prevents cached permissions from masking ITP's default blocking behavior.
Trade-offs and Limitations
The primary trade-off when fighting ITP is between user friction and session persistence. Using the Storage Access API introduces a popup or a required click, which can degrade the user experience. Alternatively, moving to a fully first-party architecture (where the auth and app share the exact same domain) removes the ITP restriction but may complicate your DNS and SSL certificate management.
Additionally, remember that ITP behavior can vary between iOS and macOS versions. A solution that works on a MacBook may still trigger a prompt on an iPhone due to stricter mobile privacy defaults.
Actionable Summary
To ensure your Safari users stay logged in, move away from document.cookie for critical session management and use HttpOnly cookies set via server headers, which are less likely to be capped than JavaScript-set cookies. For cross-domain requirements, implement the Storage Access API and provide a clear UI explanation to the user as to why the permission is needed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.