All guides

Cookies inside iframes

A cookie in a cross-site iframe is a third-party cookie, and it needs SameSite=None and Secure to be sent at all. Safari blocks it by default, and Firefox keeps a separate copy for each top site. Partitioned cookies and the Storage Access API work around these limits.

6 min read · Updated

First-party or third-party

A browser compares the site of the framed page with the site of the top page. A site is the scheme plus the registrable domain, for example https://partner.example.

Top pageFramed pageCookies in the frame
https://www.your-site.comhttps://app.your-site.comSame site. They act like first-party cookies.
https://partner.examplehttps://your-site.comCross-site. They are third-party cookies.

All the problems below apply only to the cross-site case. If you control both sites, the simplest fix is to put the frame on a subdomain of the top site.

Step 1: SameSite=None and Secure

The SameSite attribute decides if a cookie goes with cross-site requests:

SameSite valueSent in a cross-site iframe?
StrictNo
LaxNo
NoneYes, if the browser allows third-party cookies
Not setChrome treats it as Lax, so no

A cookie with SameSite=None must also have Secure. Without Secure, the browser rejects the cookie. So the page must also use HTTPS.

Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=None

This is required, but it is often not enough. The browser can still block the cookie.

Step 2: know what each browser blocks

BrowserThird-party cookies by default
SafariBlocked by Intelligent Tracking Prevention
FirefoxKept in a separate cookie store for each top site (Total Cookie Protection)
ChromeAllowed. Blocked in Incognito and when the user turns on blocking

In Firefox, your frame can set and read cookies. But the cookies from partner.example are not the same cookies your site has when the user visits it directly. A user who is signed in on your-site.com is not signed in inside the frame.

Test in Safari and in a Chrome Incognito window. Many users have these settings, and a page that works in normal Chrome can fail there.

Step 3: pick a fix that works in every browser

Option A: Partitioned cookies (CHIPS)

CHIPS means Cookies Having Independent Partitioned State. Add the Partitioned attribute, and the browser keeps one copy of the cookie for each top site:

Set-Cookie: __Host-session=abc123; Path=/; Secure; HttpOnly; SameSite=None; Partitioned
  • A Partitioned cookie must have Secure.
  • The __Host- prefix keeps the cookie on one host. It also needs Path=/ and no Domain.
  • MDN marks Partitioned as Baseline since December 2025. Chrome, Edge, Firefox, and Safari support it.

Use this when the frame needs its own state on each partner site, for example a chat widget or a cart. It does not share a login with your main site. The user signs in once for each top site.

Option B: the Storage Access API

The Storage Access API lets the frame ask for its unpartitioned cookies, the same cookies your site has as a first party.

// Runs inside the iframe, from a click handler
async function askForCookies() {
  if (await document.hasStorageAccess()) return true;
  try {
    await document.requestStorageAccess();
    location.reload(); // load again so the request sends the cookies
    return true;
  } catch {
    return false; // show a "Sign in" button that opens a new tab
  }
}

document.getElementById("enable").addEventListener("click", askForCookies);

Rules:

  • Call requestStorageAccess() from a click or tap. A call without a user gesture is denied, unless the user already granted access.
  • The user must have used your site directly, as a top page, recently. Firefox uses a 30-day window.
  • Safari and Chrome show a prompt to the user. Firefox prompts only after an origin asks on several sites.
  • If the iframe has a sandbox, the parent must add allow-storage-access-by-user-activation, allow-scripts, and allow-same-origin.
  • Access fades after 30 days of browser use without user interaction. Each interaction extends it by 30 days. Firefox uses 30 calendar days.

Option C: no cookies in the frame

You can also skip cookies. The parent page gets a short-lived token from your API and sends it to the frame with postMessage. The frame keeps the token in memory and sends it in an Authorization header. This works in all browsers, but you must protect the token like a password.

Check the frame loads at all

Cookie problems come after the frame loads. Paste the framed URL into the iframe tester to rule out a blocked frame first. For sign-in loops, see Login doesn't stick in an iframe.

Each browser writes its own note when it blocks a cookie in a frame. These pages show the exact text, the cause, and the fix:

Sources

Check your page now

Know before you embed.

Free, no sign-up, nothing stored. Paste a URL and get a verdict, a live preview, and the fix.