Safari’s ITP 2.3 Cookie Block: A Practical Guide to the Storage Access API
Safari blocks third-party cookies by default under ITP 2.3. Learn how the Storage Access API restores limited access after a user gesture, and how to test the behavior in Safari 15+.
26 May 2026, 09:34 UTC

If your analytics dashboard suddenly shows zero traffic from iPhone users, or an embedded widget renders blank in Safari while working fine in Chrome, the culprit is often Safari’s Intelligent Tracking Prevention (ITP). Since ITP 2.3, WebKit blocks third-party cookies by default. The only sanctioned way for a third-party frame to regain storage access is the Storage Access API, and it requires a deliberate user gesture. This article walks through what changed, how to request access correctly, and how to verify the behavior without guessing.
What ITP 2.3 Changes for Third-Party Content
Intelligent Tracking Prevention is Safari’s privacy system for limiting cross-site tracking. ITP 2.3 made a hard cut: third-party cookies are no longer set or sent in cross-site contexts unless the user has interacted with the embedded domain before. For developers, this means a script loaded from analytics.example inside publisher.site cannot read its own cookies by default. The request simply never carries the cookie header, and client-side storage calls may fail or return empty results.
The Storage Access API Is a Gate, Not a Switch
The Storage Access API, exposed as document.requestStorageAccess(), lets a third-party frame ask the browser for unpartitioned cookie and storage access. It returns a Promise. Critically, Safari requires a user gesture—such as a tap or click—before the promise can resolve. This is not a background refresh or an automatic retry; it is an explicit permission moment. If your analytics initialization runs on page load without any interaction, the call will reject.
Worked Example: Requesting Access After a Click
Run the following in the Safari 15+ Web Console (Develop > Show Web Console) after loading a page that embeds your third-party iframe, or embed it directly in your page. Replace the placeholder domain with your actual tracking endpoint.
<button id="grant-access">Enable analytics</button>
<script>
const TRACKING_DOMAIN = 'https://analytics.example'; // replace with your domain
document.getElementById('grant-access').addEventListener('click', async () => {
try {
await document.requestStorageAccess();
// Access granted: cookies and localStorage for TRACKING_DOMAIN
// are now available in this third-party context.
console.log('Storage access granted.');
} catch (err) {
console.error('Storage access denied:', err);
}
});
</script>
The button click satisfies the user-gesture requirement. If the promise resolves, subsequent same-origin requests from that frame should include cookies. If it rejects, confirm that the click actually targeted the document inside the iframe and that Safari’s cross-site restrictions are active.
Partitioned Storage and the 5MB Ceiling
Even when access is granted, WebKit partitions storage for third-party contexts to limit fingerprinting. This means an embedded iframe may see a different localStorage namespace than a top-level visit to the same domain. The practical effect is unexpected cache misses: a user’s preferences saved in the widget on Site A are invisible when the same widget loads on Site B. Additionally, Safari caps localStorage and sessionStorage at roughly 5MB per origin. The cap is a privacy mitigation, not a bug, so plan your client-side storage budget accordingly.
Testing Without Guesswork
Safari provides a Develop menu toggle, Disable Cross-Origin Restrictions, which relaxes ITP for local debugging. Use it to confirm that your code works when cookies are allowed, then re-enable it to test the blocked path. To inspect storage limits, run Object.keys(localStorage).length in the console; it returns the number of stored keys, not bytes, but it is a quick sanity check. Because Storage Access API behavior varies across Safari 14 through 17, verify on the specific versions your audience uses. Treat any single-version test as provisional.
Ship for the Blocked Path First
Do not treat third-party cookies as a reliable transport in Safari. If you control the top-level page, move analytics to a first-party subdomain or use server-side tagging. If you must operate in a third-party frame, wrap initialization behind an explicit consent button that calls requestStorageAccess(). Then test with cross-origin restrictions enabled, because that is the world your users actually inhabit. This article reflects documented ITP 2.3 behavior; confirm current Safari release notes before final implementation.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.