{"id":418,"date":"2025-05-28T10:00:00","date_gmt":"2025-05-28T10:00:00","guid":{"rendered":"https:\/\/dentonsgroup.com\/?p=418"},"modified":"2025-05-30T15:33:18","modified_gmt":"2025-05-30T15:33:18","slug":"reliably-detecting-third-party-cookie-blocking-in-2025","status":"publish","type":"post","link":"https:\/\/dentonsgroup.com\/index.php\/2025\/05\/28\/reliably-detecting-third-party-cookie-blocking-in-2025\/","title":{"rendered":"Reliably Detecting\u00a0Third-Party Cookie Blocking\u00a0In 2025"},"content":{"rendered":"

Reliably Detecting\u00a0Third-Party Cookie Blocking\u00a0In 2025<\/title><\/p>\n<article>\n<header>\n<h1>Reliably Detecting\u00a0Third-Party Cookie Blocking\u00a0In 2025<\/h1>\n<address>Mikhail Prosmitskiy<\/address>\n<p> 2025-05-28T10:00:00+00:00<br \/>\n 2025-05-30T15:03:14+00:00<br \/>\n <\/header>\n<p>The web is beginning to part ways with third-party cookies, a technology it once heavily relied on. <a href=\"https:\/\/en.wikipedia.org\/wiki\/HTTP_cookie\">Introduced in 1994 by Netscape<\/a> to support features like virtual shopping carts, cookies have long been a staple of web functionality. However, concerns over <strong>privacy<\/strong> and <strong>security<\/strong> have led to a concerted effort to eliminate them. The World Wide Web Consortium Technical Architecture Group (W3C TAG) <a href=\"https:\/\/w3ctag.github.io\/web-without-3p-cookies\/\">has been vocal in advocating<\/a> for the complete removal of third-party cookies from the web platform.<\/p>\n<p>Major browsers (Chrome, Safari, Firefox, and Edge) are responding by phasing them out, though the transition is gradual. While this shift enhances user privacy, it also disrupts legitimate functionalities that rely on third-party cookies, such as single sign-on (SSO), fraud prevention, and embedded services. And because there is still no universal ban in place and many essential web features continue to depend on these cookies, developers must detect when third-party cookies are blocked so that applications can respond gracefully.<\/p>\n<h2 id=\"don-t-let-silent-failures-win-why-cookie-detection-still-matters\">Don\u2019t Let Silent Failures Win: Why Cookie Detection Still Matters<\/h2>\n<p>Yes, the ideal solution is to move away from third-party cookies altogether and redesign our integrations using privacy-first, purpose-built alternatives as soon as possible. But in reality, that migration can take months or even years, especially for legacy systems or third-party vendors. Meanwhile, users are already browsing with third-party cookies disabled and often have no idea that anything is missing.<\/p>\n<p>Imagine a travel booking platform that embeds an iframe from a third-party partner to display live train or flight schedules. This embedded service uses a cookie on its own domain to authenticate the user and personalize content, like showing saved trips or loyalty rewards. But when the browser blocks third-party cookies, the iframe cannot access that data. Instead of a seamless experience, the user sees an error, a blank screen, or a login prompt that doesn\u2019t work.<\/p>\n<p>And while your team is still planning a long-term integration overhaul, this is already happening to real users. They don\u2019t see a cookie policy; they just see a broken booking flow.<\/p>\n<blockquote class=\"pull-quote\">\n<p>\n <a class=\"pull-quote__link\" aria-label=\"Share on Twitter\" href=\"https:\/\/twitter.com\/share?text=%0aDetecting%20third-party%20cookie%20blocking%20isn%e2%80%99t%20just%20good%20technical%20hygiene%20but%20a%20frontline%20defense%20for%20user%20experience.%0a&url=https:\/\/smashingmagazine.com%2f2025%2f05%2freliably-detecting-third-party-cookie-blocking-2025%2f\"><\/p>\n<p>Detecting third-party cookie blocking isn\u2019t just good technical hygiene but a frontline defense for user experience.<\/p>\n<p> <\/a>\n <\/p>\n<div class=\"pull-quote__quotation\">\n<div class=\"pull-quote__bg\">\n <span class=\"pull-quote__symbol\">\u201c<\/span><\/div>\n<\/p><\/div>\n<\/blockquote>\n<h2 id=\"why-it-s-hard-to-tell-if-third-party-cookies-are-blocked\">Why It\u2019s Hard To Tell If Third-Party Cookies Are Blocked<\/h2>\n<p>Detecting whether third-party cookies are supported isn\u2019t as simple as calling <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Navigator\/cookieEnabled\"><code>navigator.cookieEnabled<\/code><\/a>. Even a well-intentioned check like this one may look safe, but it still won\u2019t tell you what you actually need to know:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-javascript\">\/\/ DOES NOT detect third-party cookie blocking\nfunction areCookiesEnabled() {\n if (navigator.cookieEnabled === false) {\n return false;\n }\n\n try {\n document.cookie = \"test_cookie=1; SameSite=None; Secure\";\n const hasCookie = document.cookie.includes(\"test_cookie=1\");\n document.cookie = \"test_cookie=; Max-Age=0; SameSite=None; Secure\";\n\n return hasCookie;\n } catch (e) {\n return false;\n }\n}\n<\/code><\/pre>\n<\/div>\n<p>This function only confirms that cookies work in the current (first-party) context. <strong>It says nothing about third-party scenarios<\/strong>, like an iframe on another domain. Worse, it\u2019s misleading: in some browsers, <code>navigator.cookieEnabled<\/code> may still return <code>true<\/code> inside a third-party iframe even when cookies are blocked. Others might behave differently, leading to inconsistent and unreliable detection.<\/p>\n<p>These cross-browser inconsistencies — combined with the limitations of <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Document\/cookie\"><code>document.cookie<\/code><\/a> — make it clear that there is <strong>no shortcut for detection<\/strong>. To truly detect third-party cookie blocking, we need to understand <em>how<\/em> different browsers actually behave in embedded third-party contexts.<\/p>\n<div data-audience=\"non-subscriber\" data-remove=\"true\" class=\"feature-panel-container\">\n<aside class=\"feature-panel\">\n<div class=\"feature-panel-left-col\">\n<div class=\"feature-panel-description\">\n<p>Meet <strong><a data-instant href=\"https:\/\/www.smashingconf.com\/online-workshops\/\">Smashing Workshops<\/a><\/strong> on <strong>front-end, design & UX<\/strong>, with practical takeaways, live sessions, <strong>video recordings<\/strong> and a friendly Q&A. With Brad Frost, St\u00e9ph Walter and <a href=\"https:\/\/smashingconf.com\/online-workshops\/workshops\">so many others<\/a>.<\/p>\n<p><a data-instant href=\"smashing-workshops\" class=\"btn btn--green btn--large\">Jump to the workshops \u21ac<\/a><\/div>\n<\/div>\n<div class=\"feature-panel-right-col\"><a data-instant href=\"smashing-workshops\" class=\"feature-panel-image-link\"><\/p>\n<div class=\"feature-panel-image\">\n<img decoding=\"async\" loading=\"lazy\" class=\"feature-panel-image-img lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Feature Panel\" width=\"257\" height=\"355\" data-src=\"\/images\/smashing-cat\/cat-scubadiving-panel.svg\"><\/p>\n<\/div>\n<p><\/a>\n<\/div>\n<\/aside>\n<\/div>\n<h2 id=\"how-modern-browsers-handle-third-party-cookies\">How Modern Browsers Handle Third-Party Cookies<\/h2>\n<p>The behavior of modern browsers directly affects which detection methods will work and which ones silently fail.<\/p>\n<h3 id=\"safari-full-third-party-cookie-blocking\">Safari: Full Third-Party Cookie Blocking<\/h3>\n<p>Since <a href=\"https:\/\/webkit.org\/blog\/10218\/full-third-party-cookie-blocking-and-more\/\">version 13.1<\/a>, Safari blocks all third-party cookies by default, with no exceptions, even if the user previously interacted with the embedded domain. This policy is part of <a href=\"https:\/\/webkit.org\/tracking-prevention\/#intelligent-tracking-prevention-itp\">Intelligent Tracking Prevention (ITP)<\/a>.<\/p>\n<p>For embedded content (such as an SSO iframe) that requires cookie access, Safari exposes the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Storage_Access_API\">Storage Access API<\/a>, which requires a user gesture to grant storage permission. As a result, a test for third-party cookie support will nearly always fail in Safari unless the iframe explicitly requests access via this API.<\/p>\n<h3 id=\"firefox-cookie-partitioning-by-design\">Firefox: Cookie Partitioning By Design<\/h3>\n<p>Firefox\u2019s <a href=\"https:\/\/support.mozilla.org\/en-US\/kb\/total-cookie-protection-and-website-breakage-faq#w_what-is-total-cookie-protection\">Total Cookie Protection<\/a> isolates cookies on a per-site basis. Third-party cookies can still be set and read, but they are partitioned by the top-level site, meaning a cookie set by the same third-party on <em>siteA.com<\/em> and <em>siteB.com<\/em> is stored separately and cannot be shared.<\/p>\n<p>As of <a href=\"https:\/\/support.mozilla.org\/en-US\/kb\/introducing-total-cookie-protection-standard-mode\">Firefox 102<\/a>, this behavior is enabled by default in the Standard (default) mode of <a href=\"https:\/\/support.mozilla.org\/en-US\/kb\/enhanced-tracking-protection-firefox-desktop\">Enhanced Tracking Protection<\/a>. Unlike the Strict mode — which <a href=\"https:\/\/support.mozilla.org\/en-US\/kb\/enhanced-tracking-protection-firefox-desktop#w_strict-enhanced-tracking-protection\">blocks third-party cookies entirely<\/a>, similar to Safari — the Standard mode does not block them outright. Instead, it neutralizes their tracking capability by isolating them per site.<\/p>\n<p>As a result, even if a test shows that a third-party cookie was successfully set, it may be useless for cross-site logins or shared sessions due to this <strong>partitioning<\/strong>. Detection logic needs to account for that.<\/p>\n<h3 id=\"chrome-from-deprecation-plans-to-privacy-sandbox-and-industry-pushback\">Chrome: From Deprecation Plans To Privacy Sandbox (And Industry Pushback)<\/h3>\n<p>Chromium-based browsers still allow third-party cookies by default — but the story is changing. Starting with <a href=\"https:\/\/blog.chromium.org\/2019\/10\/developers-get-ready-for-new.html\">Chrome 80<\/a>, third-party cookies must be explicitly marked with <code>SameSite=None; Secure<\/code>, or they will be rejected.<\/p>\n<p>In <a href=\"https:\/\/blog.chromium.org\/2020\/01\/building-more-private-web-path-towards.html\">January 2020<\/a>, <strong>Google announced their intention<\/strong> to phase out third-party cookies by 2022. <strong>However, the timeline was updated multiple times<\/strong>, first in <a href=\"https:\/\/blog.google\/products\/chrome\/updated-timeline-privacy-sandbox-milestones\/?utm_source=chatgpt.com\">June 2021<\/a> when the company pushed the rollout to begin in mid-2023 and conclude by the end of that year. Additional postponements followed in <a href=\"https:\/\/blog.google\/products\/chrome\/update-testing-privacy-sandbox-web\/\">July 2022<\/a>, <a href=\"https:\/\/blog.google\/products\/chrome\/privacy-sandbox-tracking-protection\/\">December 2023<\/a>, and <a href=\"https:\/\/privacysandbox.com\/intl\/en_us\/news\/update-on-the-plan-for-phase-out-of-third-party-cookies-on-chrome\/\">April 2024<\/a>.<\/p>\n<p>In <a href=\"https:\/\/privacysandbox.com\/news\/privacy-sandbox-update\/\">July 2024<\/a>, <strong>Google has clarified that there is no plan to unilaterally deprecate third-party cookies or force users into a new model without consent<\/strong>. Instead, Chrome is shifting to a <strong>user-choice interface<\/strong> that will allow individuals to decide whether to block or allow third-party cookies globally.<\/p>\n<p>This change was influenced in part by <a href=\"https:\/\/www.businessinsider.com\/googles-plan-to-replace-tracking-cookies-faces-big-new-hurdles-2024-7\">substantial pushback from the advertising industry<\/a>, as well as ongoing regulatory oversight, including <a href=\"https:\/\/www.gov.uk\/cma-cases\/investigation-into-googles-privacy-sandbox-browser-changes\">scrutiny by the UK Competition and Markets Authority (CMA)<\/a> into <a href=\"https:\/\/privacysandbox.google.com\">Google\u2019s Privacy Sandbox initiative<\/a>. The CMA confirmed in a 2025 update that there is no intention to force a deprecation or trigger automatic prompts for cookie blocking.<\/p>\n<p>As for now, <strong>third-party cookies remain enabled by default in Chrome<\/strong>. The new user-facing controls and the broader Privacy Sandbox ecosystem are still in various stages of experimentation and limited rollout.<\/p>\n<h3 id=\"edge-chromium-based-tracker-focused-blocking-with-user-configurability\">Edge (Chromium-Based): Tracker-Focused Blocking With User Configurability<\/h3>\n<p>Edge (which is a Chromium-based browser) <a href=\"https:\/\/learn.microsoft.com\/en-us\/microsoftteams\/platform\/resources\/samesite-cookie-update#samesite-cookie-attribute-2020-release\">shares Chrome\u2019s handling of third-party cookies<\/a>, including the <code>SameSite=None; Secure<\/code> requirement. Additionally, Edge introduces <a href=\"https:\/\/learn.microsoft.com\/en-us\/microsoft-edge\/web-platform\/tracking-prevention\">Tracking Prevention<\/a> modes: Basic, Balanced (default), and Strict. In Balanced mode, it blocks known third-party trackers using Microsoft\u2019s maintained list but allows many third-party cookies that are not classified as trackers. Strict mode blocks more resource loads than Balanced, which may result in some websites not behaving as expected.<\/p>\n<h3 id=\"other-browsers-what-about-them\">Other Browsers: What About Them?<\/h3>\n<p>Privacy-focused browsers, like Brave, <a href=\"https:\/\/support.brave.com\/hc\/en-us\/articles\/360054509991-How-do-I-manage-Cookies-and-Site-data-in-Brave-on-Android?utm_source=chatgpt.com\">block third-party cookies by default<\/a> as part of their strong anti-tracking stance.<\/p>\n<p>Internet Explorer (IE) 11 <a href=\"https:\/\/support.microsoft.com\/en-us\/topic\/description-of-cookies-ad01aa7e-66c9-8ab2-7898-6652c100999d\">allowed third-party cookies depending on user privacy settings<\/a> and the presence of <a href=\"https:\/\/www.w3.org\/P3P\/\">Platform for Privacy Preferences (P3P)<\/a> headers. However, IE usage is now negligible. Notably, the default \u201cMedium\u201d privacy setting in IE could block third-party cookies unless a valid P3P policy was present.<\/p>\n<p>Older versions of Safari had partial third-party cookie restrictions (such as <em>\u201cAllow from websites I visit\u201d<\/em>), but, as mentioned before, this was replaced with full blocking via ITP.<\/p>\n<p><strong>As of 2025, all major browsers either block or isolate third-party cookies by default, with the exception of Chrome, which still allows them in standard browsing mode pending the rollout of its new user-choice model.<\/strong><\/p>\n<p>To account for these variations, your detection strategy must be grounded in real-world testing — specifically by reproducing a genuine third-party context such as loading your script within an iframe on a cross-origin domain — rather than relying on browser names or versions.<\/p>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"overview-of-detection-techniques\">Overview Of Detection Techniques<\/h2>\n<p>Over the years, many techniques have been used to detect third-party cookie blocking. Most are unreliable or obsolete. Here\u2019s a quick walkthrough of what doesn\u2019t work (and why) and what does.<\/p>\n<h3 id=\"basic-javascript-api-checks-misleading\">Basic JavaScript API Checks (Misleading)<\/h3>\n<p>As mentioned earlier, the <code>navigator.cookieEnabled<\/code> or setting <code>document.cookie<\/code> on the main page doesn\u2019t reflect cross-site cookie status:<\/p>\n<ul>\n<li>In third-party iframes, <code>navigator.cookieEnabled<\/code> often returns <code>true<\/code> even when cookies are blocked.<\/li>\n<li>Setting <code>document.cookie<\/code> in the parent doesn\u2019t test the third-party context.<\/li>\n<\/ul>\n<p>These checks are first-party only. <strong>Avoid using them for detection.<\/strong><\/p>\n<h3 id=\"storage-hacks-via-localstorage-obsolete\">Storage Hacks Via <code>localStorage<\/code> (Obsolete)<\/h3>\n<p>Previously, some developers inferred cookie support by checking if <code>window.localStorage<\/code> worked inside a third-party iframe — which is especially useful against older Safari versions that blocked all third-party storage.<\/p>\n<p>Modern browsers often allow <code>localStorage<\/code> even when cookies are blocked. <strong>This leads to false positives and is no longer reliable.<\/strong><\/p>\n<h3 id=\"server-assisted-cookie-probe-heavyweight\">Server-Assisted Cookie Probe (Heavyweight)<\/h3>\n<p>One classic method involves setting a cookie from a third-party domain via HTTP and then checking if it comes back:<\/p>\n<ol>\n<li>Load a script\/image from a third-party server that sets a cookie.<\/li>\n<li>Immediately load another resource, and the server checks whether the cookie was sent.<\/li>\n<\/ol>\n<p>This works, but it:<\/p>\n<ul>\n<li>Requires custom server-side logic,<\/li>\n<li>Depends on HTTP caching, response headers, and cookie attributes (<code>SameSite=None; Secure<\/code>), and<\/li>\n<li>Adds development and infrastructure complexity.<\/li>\n<\/ul>\n<p>While this is <strong>technically valid<\/strong>, it is not suitable for a front-end-only approach, which is our focus here.<\/p>\n<h3 id=\"storage-access-api-supplemental-signal\">Storage Access API (Supplemental Signal)<\/h3>\n<p>The <code>document.hasStorageAccess()<\/code> method allows embedded third-party content to check if it has access to unpartitioned cookies:<\/p>\n<ul>\n<li><strong>Chrome<\/strong><br \/>\nSupports <code>hasStorageAccess()<\/code> and <code>requestStorageAccess()<\/code> starting from <a href=\"https:\/\/privacysandbox.google.com\/cookies\/storage-access-api#top-level_page_access\">version 119<\/a>. Additionally, <code>hasUnpartitionedCookieAccess()<\/code> is available as an alias for <code>hasStorageAccess()<\/code> from <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Document\/hasUnpartitionedCookieAccess#browser_compatibility\">version 125<\/a> onwards.<\/li>\n<li><strong>Firefox<\/strong><br \/>\n<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Storage_Access_API#browser_compatibility\">Supports<\/a> both <code>hasStorageAccess()<\/code> and <code>requestStorageAccess()<\/code> methods.<\/li>\n<li><strong>Safari<\/strong><br \/>\n<a href=\"https:\/\/webkit.org\/blog\/11545\/updates-to-the-storage-access-api\/\">Supports the Storage Access API<\/a>. However, <strong>access must always be triggered by a user interaction<\/strong>. For example, even calling <code>requestStorageAccess()<\/code> without a direct user gesture (like a click) is ignored.<\/li>\n<\/ul>\n<p>Chrome and Firefox also support the API, and in those browsers, it may work automatically or based on browser heuristics or site engagement.<\/p>\n<p>This API is particularly useful for detecting scenarios where cookies are present but partitioned (e.g., Firefox\u2019s Total Cookie Protection), as it helps determine if the iframe has unrestricted cookie access. But for now, it\u2019s still best used as a <strong>supplemental signal<\/strong>, rather than a standalone check.<\/p>\n<h3 id=\"iframe-postmessage-best-practice\">iFrame + <code>postMessage<\/code> (Best Practice)<\/h3>\n<p>Despite the existence of the Storage Access API, <strong>at the time of writing, this remains the most reliable and browser-compatible method<\/strong>:<\/p>\n<ol>\n<li>Embed a hidden iframe from a third-party domain.<\/li>\n<li>Inside the iframe, attempt to set a test cookie.<\/li>\n<li>Use <code>window.postMessage<\/code> to report success or failure to the parent.<\/li>\n<\/ol>\n<p>This approach works across all major browsers (when properly configured), requires no server (kind of, more on that next), and simulates a real-world third-party scenario.<\/p>\n<p>We\u2019ll implement this step-by-step next.<\/p>\n<h3 id=\"bonus-sec-fetch-storage-access\">Bonus: <code>Sec-Fetch-Storage-Access<\/code><\/h3>\n<p>Chrome (starting in <a href=\"https:\/\/privacysandbox.google.com\/blog\/storage-access-headers-133\">version 133<\/a>) is introducing <code>Sec-Fetch-Storage-Access<\/code>, an HTTP request header sent with cross-site requests to indicate whether the iframe has access to unpartitioned cookies. <strong>This header is only visible to servers and cannot be accessed via JavaScript.<\/strong> It\u2019s useful for back-end analytics but not applicable for client-side cookie detection.<\/p>\n<p>As of May 2025, this feature is only implemented in Chrome and is not supported by other browsers. However, it\u2019s still good to know that it\u2019s part of the evolving ecosystem.<\/p>\n<h2 id=\"step-by-step-detecting-third-party-cookies-via-iframe\">Step-by-Step: Detecting Third-Party Cookies Via iFrame<\/h2>\n<p>So, what did I mean when I said that the last method we looked at \u201crequires no server\u201d? While this method doesn\u2019t require any back-end logic (like server-set cookies or response inspection), it does require access to a separate domain — or at least a cross-site subdomain — to simulate a third-party environment. This means the following:<\/p>\n<ul>\n<li>You must serve the test page from a different domain or public subdomain, e.g., <code>example.com<\/code> and <code>cookietest.example.com<\/code>,<\/li>\n<li>The domain needs HTTPS (for <code>SameSite=None; Secure<\/code> cookies to work), and<\/li>\n<li>You\u2019ll need to host a simple static file (the test page), even if no server code is involved.<\/li>\n<\/ul>\n<p>Once that\u2019s set up, the rest of the logic is fully client-side.<\/p>\n<h3 id=\"step-1-create-a-cookie-test-page-on-a-third-party-domain\">Step 1: Create A Cookie Test Page (On A Third-Party Domain)<\/h3>\n<p>Minimal version (e.g., <code>https:\/\/cookietest.example.com\/cookie-check.html<\/code>):<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-html\"><!DOCTYPE html>\n<html>\n <body>\n <script>\n document.cookie = \"thirdparty_test=1; SameSite=None; Secure; Path=\/;\";\n const cookieFound = document.cookie.includes(\"thirdparty_test=1\");\n \n const sendResult = (status) => window.parent?.postMessage(status, \"*\");\n \n if (cookieFound && document.hasStorageAccess instanceof Function) {\n document.hasStorageAccess().then((hasAccess) => {\n sendResult(hasAccess ? \"TP_COOKIE_SUPPORTED\" : \"TP_COOKIE_BLOCKED\");\n }).catch(() => sendResult(\"TP_COOKIE_BLOCKED\"));\n } else {\n sendResult(cookieFound ? \"TP_COOKIE_SUPPORTED\" : \"TP_COOKIE_BLOCKED\");\n }\n <\/script>\n <\/body>\n<\/html>\n<\/code><\/pre>\n<\/div>\n<p>Make sure the page is served over HTTPS, and the cookie uses <code>SameSite=None; Secure<\/code>. Without these attributes, modern browsers will silently reject it.<\/p>\n<h3 id=\"step-2-embed-the-iframe-and-listen-for-the-result\">Step 2: Embed The iFrame And Listen For The Result<\/h3>\n<p>On your main page:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-javascript\">function checkThirdPartyCookies() {\n return new Promise((resolve) => {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.src = \"https:\/\/cookietest.example.com\/cookie-check.html\"; \/\/ your subdomain\n document.body.appendChild(iframe);\n\n let resolved = false;\n const cleanup = (result, timedOut = false) => {\n if (resolved) return;\n resolved = true;\n window.removeEventListener('message', onMessage);\n iframe.remove();\n resolve({ thirdPartyCookiesEnabled: result, timedOut });\n };\n\n const onMessage = (event) => {\n if ([\"TP_COOKIE_SUPPORTED\", \"TP_COOKIE_BLOCKED\"].includes(event.data)) {\n cleanup(event.data === \"TP_COOKIE_SUPPORTED\", false);\n }\n };\n\n window.addEventListener('message', onMessage);\n setTimeout(() => cleanup(false, true), 1000);\n });\n}\n<\/code><\/pre>\n<\/div>\n<p>Example usage:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-javascript\">checkThirdPartyCookies().then(({ thirdPartyCookiesEnabled, timedOut }) => {\n if (!thirdPartyCookiesEnabled) {\n someCookiesBlockedCallback(); \/\/ Third-party cookies are blocked.\n if (timedOut) {\n \/\/ No response received (iframe possibly blocked).\n \/\/ Optional fallback UX goes here.\n someCookiesBlockedTimeoutCallback();\n };\n }\n});\n<\/code><\/pre>\n<\/div>\n<h3 id=\"step-3-enhance-detection-with-the-storage-access-api\">Step 3: Enhance Detection With The Storage Access API<\/h3>\n<p>In Safari, even when third-party cookies are blocked, users can manually grant access through the Storage Access API — but only in response to a user gesture.<\/p>\n<p>Here\u2019s how you could implement that in your iframe test page:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-html\"><button id=\"enable-cookies\">This embedded content requires cookie access. Click below to continue.<\/button>\n\n<script>\n document.getElementById('enable-cookies')?.addEventListener('click', async () => {\n if (document.requestStorageAccess && typeof document.requestStorageAccess === 'function') {\n try {\n const granted = await document.requestStorageAccess();\n if (granted !== false) {\n window.parent.postMessage(\"TP_STORAGE_ACCESS_GRANTED\", \"*\");\n } else {\n window.parent.postMessage(\"TP_STORAGE_ACCESS_DENIED\", \"*\");\n }\n } catch (e) {\n window.parent.postMessage(\"TP_STORAGE_ACCESS_FAILED\", \"*\");\n }\n }\n });\n<\/script>\n<\/code><\/pre>\n<\/div>\n<p>Then, on the parent page, you can listen for this message and retry detection if needed:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-javascript\">\/\/ Inside the same `onMessage` listener from before:\nif (event.data === \"TP_STORAGE_ACCESS_GRANTED\") {\n \/\/ Optionally: retry the cookie test, or reload iframe logic\n checkThirdPartyCookies().then(handleResultAgain);\n}\n<\/code><\/pre>\n<\/div>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"bonus-a-purely-client-side-fallback-not-perfect-but-sometimes-necessary\">(Bonus) A Purely Client-Side Fallback (Not Perfect, But Sometimes Necessary)<\/h2>\n<p>In some situations, you might not have access to a second domain or can\u2019t host third-party content under your control. That makes the iframe method unfeasible.<\/p>\n<p>When that\u2019s the case, your best option is to <strong>combine multiple signals<\/strong> — basic cookie checks, <code>hasStorageAccess()<\/code>, <code>localStorage<\/code> fallbacks, and maybe even passive indicators like load failures or timeouts — to <strong>infer<\/strong> whether third-party cookies are likely blocked.<\/p>\n<p>The important caveat: <strong>This will never be 100% accurate.<\/strong> But, in constrained environments, \u201cbetter something than nothing\u201d may still improve the UX.<\/p>\n<p>Here\u2019s a basic example:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-javascript\">async function inferCookieSupportFallback() {\n let hasCookieAPI = navigator.cookieEnabled;\n let canSetCookie = false;\n let hasStorageAccess = false;\n\n try {\n document.cookie = \"testfallback=1; SameSite=None; Secure; Path=\/;\";\n canSetCookie = document.cookie.includes(\"test_fallback=1\");\n\n document.cookie = \"test_fallback=; Max-Age=0; Path=\/;\";\n } catch (_) {\n canSetCookie = false;\n }\n\n if (typeof document.hasStorageAccess === \"function\") {\n try {\n hasStorageAccess = await document.hasStorageAccess();\n } catch (_) {}\n }\n\n return {\n inferredThirdPartyCookies: hasCookieAPI && canSetCookie && hasStorageAccess,\n raw: { hasCookieAPI, canSetCookie, hasStorageAccess }\n };\n}\n<\/code><\/pre>\n<\/div>\n<p>Example usage:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-javascript\">inferCookieSupportFallback().then(({ inferredThirdPartyCookies }) => {\n if (inferredThirdPartyCookies) {\n console.log(\"Cookies likely supported. Likely, yes.\");\n } else {\n console.warn(\"Cookies may be blocked or partitioned.\");\n \/\/ You could inform the user or adjust behavior accordingly\n }\n});\n<\/code><\/pre>\n<\/div>\n<p>Use this fallback when:<\/p>\n<ul>\n<li>You\u2019re building a JavaScript-only widget embedded on unknown sites,<\/li>\n<li>You don\u2019t control a second domain (or the team refuses to add one), or<\/li>\n<li>You just need <em>some<\/em> visibility into user-side behavior (e.g., debugging UX issues).<\/li>\n<\/ul>\n<p><strong>Don\u2019t rely on it for security-critical logic (e.g., auth gating)!<\/strong> But it may help tailor the user experience, surface warnings, or decide whether to attempt a fallback SSO flow. Again, it\u2019s better to have something rather than nothing.<\/p>\n<h2 id=\"fallback-strategies-when-third-party-cookies-are-blocked\">Fallback Strategies When Third-Party Cookies Are Blocked<\/h2>\n<p>Detecting blocked cookies is only half the battle. Once you know they\u2019re unavailable, what can you do? Here are some practical options that might be useful for you:<\/p>\n<h3 id=\"redirect-based-flows\">Redirect-Based Flows<\/h3>\n<p>For auth-related flows, switch from embedded iframes to top-level redirects. Let the user authenticate directly on the identity provider’s site, then redirect back. It works in all browsers, but the UX might be less seamless.<\/p>\n<h3 id=\"request-storage-access\">Request Storage Access<\/h3>\n<p>Prompt the user using <code>requestStorageAccess()<\/code> after a clear UI gesture (Safari requires this). Use this to re-enable cookies <strong>without leaving the page<\/strong>.<\/p>\n<h3 id=\"token-based-communication\">Token-Based Communication<\/h3>\n<p>Pass session info directly from parent to iframe via:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Window\/postMessage\"><code>postMessage<\/code><\/a> (with required <a href=\"https:\/\/owasp.org\/www-project-web-security-testing-guide\/latest\/4-Web_Application_Security_Testing\/11-Client-side_Testing\/11-Testing_Web_Messaging\"><code>origin<\/code><\/a>);<\/li>\n<li>Query params (e.g., signed JWT in iframe URL).<\/li>\n<\/ul>\n<p>This avoids reliance on cookies entirely but requires coordination between both sides:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-javascript\">\/\/ Parent\nconst iframe = document.getElementById('my-iframe');\n\niframe.onload = () => {\n const token = getAccessTokenSomehow(); \/\/ JWT or anything else\n iframe.contentWindow.postMessage(\n { type: 'AUTH_TOKEN', token },\n 'https:\/\/iframe.example.com' \/\/ Set the correct origin!\n );\n};\n\n\/\/ iframe\nwindow.addEventListener('message', (event) => {\n if (event.origin !== 'https:\/\/parent.example.com') return;\n\n const { type, token } = event.data;\n\n if (type === 'AUTH_TOKEN') {\n validateAndUseToken(token); \/\/ process JWT, init session, etc\n }\n});\n<\/code><\/pre>\n<\/div>\n<h3 id=\"partitioned-cookies-chips\">Partitioned Cookies (CHIPS)<\/h3>\n<p>Chrome (since version 114) and other Chromium-based browsers now support cookies with the Partitioned attribute (known as <a href=\"https:\/\/privacysandbox.google.com\/cookies\/chips\">CHIPS<\/a>), allowing per-top-site cookie isolation. This is useful for widgets like chat or embedded forms where cross-site identity isn\u2019t needed.<\/p>\n<blockquote><p><strong>Note<\/strong>: Firefox and Safari don\u2019t support the <code>Partitioned<\/code> cookie attribute. Firefox enforces cookie partitioning by default using a different mechanism (Total Cookie Protection), while Safari blocks third-party cookies entirely.<\/p><\/blockquote>\n<p>But be careful, as they are treated as \u201cblocked\u201d by basic detection. Refine your logic if needed.<\/p>\n<h2 id=\"final-thought-transparency-transition-and-the-path-forward\">Final Thought: Transparency, Transition, And The Path Forward<\/h2>\n<p>Third-party cookies are disappearing, albeit gradually and unevenly. Until the transition is complete, your job as a developer is to bridge the gap between technical limitations and real-world user experience. That means:<\/p>\n<ul>\n<li><strong>Keep an eye on the standards.<\/strong><br \/>\nAPIs like <a href=\"https:\/\/privacysandbox.google.com\/cookies\/fedcm\">FedCM<\/a> and Privacy Sandbox features (<a href=\"https:\/\/privacysandbox.google.com\/private-advertising\/topics?hl=en\">Topics<\/a>, <a href=\"https:\/\/privacysandbox.google.com\/private-advertising\/attribution-reporting\">Attribution Reporting<\/a>, <a href=\"https:\/\/privacysandbox.google.com\/private-advertising\/fenced-frame\">Fenced Frames<\/a>) are reshaping how we handle identity and analytics without relying on cross-site cookies.<\/li>\n<li><strong>Combine detection with graceful fallback.<\/strong><br \/>\nWhether it\u2019s offering a redirect flow, using <code>requestStorageAccess()<\/code>, or falling back to token-based messaging — every small UX improvement adds up.<\/li>\n<li><strong>Inform your users.<\/strong><br \/>\nUsers shouldn’t be left wondering why something worked in one browser but silently broke in another. Don\u2019t let them feel like they did something wrong — just help them move forward. A clear, friendly message can prevent this confusion.<\/li>\n<\/ul>\n<p>The good news? You don\u2019t need a perfect solution today, just a resilient one. By detecting issues early and handling them thoughtfully, you protect both your users and your future architecture, one cookie-less browser at a time.<\/p>\n<p>And as seen with Chrome\u2019s pivot away from automatic deprecation, the transition is not always linear. Industry feedback, regulatory oversight, and evolving technical realities continue to shape the time and the solutions.<\/p>\n<p>And don\u2019t forget: <em>having something is better than nothing<\/em>.<\/p>\n<div class=\"signature\">\n <img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Smashing Editorial\" width=\"35\" height=\"46\" loading=\"lazy\" class=\"lazyload\" data-src=\"https:\/\/www.smashingmagazine.com\/images\/logo\/logo--red.png\"><br \/>\n <span>(yk)<\/span>\n<\/div>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>Reliably Detecting\u00a0Third-Party Cookie Blocking\u00a0In 2025 Reliably Detecting\u00a0Third-Party Cookie Blocking\u00a0In 2025 Mikhail Prosmitskiy 2025-05-28T10:00:00+00:00 2025-05-30T15:03:14+00:00 The web is beginning to part ways with third-party cookies, a technology it once heavily relied on. Introduced in 1994 by Netscape to support features like virtual shopping carts, cookies have long been a staple of web functionality. However, concerns over…<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-418","post","type-post","status-publish","format-standard","hentry","category-accessibility"],"_links":{"self":[{"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/posts\/418","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/comments?post=418"}],"version-history":[{"count":1,"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/posts\/418\/revisions"}],"predecessor-version":[{"id":421,"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/posts\/418\/revisions\/421"}],"wp:attachment":[{"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/media?parent=418"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/categories?post=418"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dentonsgroup.com\/index.php\/wp-json\/wp\/v2\/tags?post=418"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}