TulipLot works best in Chrome or a Chromium-based browser. Some features may be limited here.
← All posts
Embedding · · 9 min read

Why Gmail and Google Calendar never load in an iframe

Checked on 2026-08-24.

Every dashboard, portal, and "all your apps in one page" tool eventually gets the same request: put Gmail in one of the boxes. The answer is no, it has been no for a long time, and it is not going to change. What's worth writing down is why — not the hand-wave about Google being strict, but the specific mechanisms, in the order a browser hits them.

What the measurement actually says

On 2026-08-24 we requested 60 popular web apps without signing in to any of them, and recorded the framing headers that came back. The Google rows:

App Requested X-Frame-Options frame-ancestors
Gmail https://mail.google.com DENY —
Google Calendar https://calendar.google.com DENY —
Google Docs https://docs.google.com DENY —
Google Keep https://keep.google.com DENY —
Google Analytics https://analytics.google.com DENY —
YouTube https://www.youtube.com SAMEORIGIN —

Now the honest part, because it changes how you should read that table. Neither the Gmail request nor the Calendar request ever reached a mailbox or a calendar. Both were unauthenticated, and both ended on accounts.google.com — Google's sign-in page. The DENY we recorded is the sign-in page's DENY.

That's not a broken measurement; it's the accurate one. An unauthenticated frame lands exactly where our request landed. But it does mean the interesting question is what happens along the way, so we followed the chain by hand on the same day. Requesting https://mail.google.com/ took five hops. The first three stayed on mail.google.com and every one of them carried X-Frame-Options: SAMEORIGIN; the very first also carried Content-Security-Policy: frame-ancestors 'self'. The last two were on accounts.google.com, and the one that finally answered with a page carried X-Frame-Options: DENY.

Every step that renders a page refuses a third-party frame. The fourth response, a redirect on accounts.google.com, carried no framing header at all — but a redirect renders nothing, so there is nothing to frame. Only the strictness changes: Gmail permits Gmail to frame Gmail, and the sign-in page permits nothing at all. There's a general lesson in that, worth more than the Google specifics — when you check a site's framing headers, read every hop in the redirect chain, not just the first response. The header that blocks you is often not the one you went looking for.

What the block is protecting

A framed mailbox with a live session is one of the best clickjacking targets on the internet. The attack needs three things: a page the attacker controls, a real logged-in site loaded invisibly on top of it, and a button worth stealing a click on. A mailbox supplies the third in bulk — delete everything, forward all mail to this address, grant this app access to your account, confirm this device. Your click is genuine; you just never saw what it landed on. Clickjacking explained walks through the mechanics.

Then look at where the chain actually ends. accounts.google.com is not just a login form. It's the host behind account recovery, device confirmation, and the OAuth consent screen where you grant a third-party application access to your data. A stolen click on a consent screen can hand over lasting access to an account, not just one session. DENY on that host is the least surprising line in our entire data set. It would be alarming if it were anything else.

Why an extension that strips the header doesn't fix it

Browser extensions that rewrite framing headers are real, and for some sites they work fine. For Gmail they don't, and there are three separate reasons — the first two of which are each enough on their own.

The header you strip isn't the one blocking you. The frame doesn't stay on mail.google.com. It redirects to accounts.google.com, a different host, with its own DENY. An extension configured for the mail host never sees that response. You would have to grant it permission over Google's account infrastructure — the exact host that ought to be hardest to touch — for the rewrite to reach the header that matters. What a header-rewriting extension can and can't reach is its own topic, covered in Chrome's declarativeNetRequest rules.

Cookies are a second, independent gate. Loading a page in a frame on someone else's site makes the request cross-site, and browsers increasingly send a cookie on a cross-site request only when it's explicitly marked for that. MDN puts the default carefully: "Some browsers use Lax as the default value if SameSite is not specified." Browsers differ here and the rules around third-party cookies keep tightening, so the reliable summary is the negative one — a session cookie that hasn't opted in to cross-site use should not be assumed to arrive. Strip every framing header and you can still land on a login screen inside your frame, because as far as the cookie rules are concerned, you aren't logged in.

For what it's worth, the cookie the sign-in page set on our own fresh request was named __Host-GAPS, marked Secure and HttpOnly. That __Host- prefix is a rule the browser enforces on how the cookie may be set: MDN describes it as requiring Secure, no Domain attribute, and Path=/, which "guarantees that such cookies are only sent to the host that set them." It's a signal about how tightly this is held, not a loophole.

Applications can also check for themselves. A page can compare window.top with window.self and refuse to run when the two differ, and login flows in particular have a long history of doing this. We can't tell you from a header read whether any specific Google page does it — that's a claim about JavaScript we didn't verify, and we're not going to assert it. What we can say is that the technique exists, doesn't depend on headers at all, and is not something an extension that rewrites response headers can touch.

Why a reverse proxy doesn't fix it either

The other workaround people reach for is a proxy: your own server fetches Gmail, strips the headers, and serves the result from your domain, so the browser sees a same-origin page and frames it happily.

Look at what that requires. Your credentials, your session cookie, and your two-factor step all now flow through a server that isn't Google. Either you're not logged in — in which case you've proxied a sign-in page — or you've handed a machine in the middle everything it needs to be you. The account protections that make Google worth trusting exist specifically to prevent that arrangement. Reverse-proxy embedding goes through the whole approach, including the narrow cases where it's legitimate.

What Google does support

Google's position isn't "never embed anything." It's that the applications are closed and the purpose-built endpoints are open. Two we checked on 2026-08-24:

Google Calendar has a public embed endpoint. We requested a public calendar through https://calendar.google.com/calendar/embed with a src parameter — the US Holidays calendar — and got back HTTP 200, a page titled "Holidays in United States", and no X-Frame-Options header and no frame-ancestors directive. That endpoint is built to be framed. Google's own Calendar help describes making a calendar public and then copying an "Embed code" out of the settings screen; we didn't sign in to generate one, so what we can vouch for is the endpoint's behaviour rather than the exact markup Calendar hands you.

Be precise about what that is, though. It's a read-only view of a calendar that is already public to anyone with the link. It isn't your account, it doesn't show your other calendars, and it isn't a way into the Calendar application. We tested the public case only; a calendar that isn't public still needs a signed-in viewer, which puts you back in the cookie problem above.

YouTube works the same way. The site itself sent X-Frame-Options: SAMEORIGIN in our table, and yet embedded YouTube players are everywhere. That's because the player lives at a different path: we requested https://www.youtube.com/embed/ with a video ID on 2026-08-24 and got HTTP 200 with no X-Frame-Options header. Same host, one endpoint closed and one open, on purpose.

Gmail has no equivalent. We know of no public endpoint that renders a mailbox in a frame, and given what a mailbox is, that's the expected answer rather than an oversight. Calendar publishes calendars and YouTube publishes players. Nobody publishes an inbox.

The honest answer for a dashboard

If you're building or choosing a tool that holds several apps in one view, the right design for this category is a launcher, not a frame: a cell that shows the app's name and opens it in its own tab in one click. It sounds like a downgrade and it isn't. You get the real application, with its real login, its real session, and its real security, one click away — rather than a broken frame or a proxy that hollows all three out.

The distinction that actually matters is between apps that refuse the frame and apps that just need help with it, because those need different answers. Why some sites won't load in a dashboard covers where that line falls, and Gmail and Google Calendar side by side covers the arrangements that do work when you want both in view.

Want to know where your own list of apps falls? Can I embed this site in an iframe? has the measured headers for all 60 apps we tested, with the raw values and the date on every row.

Questions

Will Gmail ever be embeddable in another site?

There's no sign of it, and the reasons aren't the kind that get patched. The header is the outermost layer; underneath it sit the cross-site cookie rules and an account infrastructure whose whole job is to make sure a click on a consent screen is a click the account holder actually saw. A framed mailbox undermines all of that, and it would be a strange product decision to reverse. Treat it as a permanent property of the web, not a feature request.

Is there a Gmail embed URL like the Calendar one?

Not that we're aware of. Calendar has a public embed endpoint, which we confirmed serves a framable page for a public calendar, and YouTube has its player path. Gmail has no comparable endpoint, and the difference makes sense: those endpoints publish something you deliberately made public, and a mailbox is the opposite of that by definition.

Does the Google Calendar embed show my private calendar?

Only in the sense that any calendar you have deliberately made public can be embedded. The case we tested was a fully public calendar, fetched with no session at all, and it returned a normal framable page. A calendar that isn't public still requires a viewer who is signed in and has access, which means the frame depends on cookies being sent cross-site — a separate problem from the framing headers, and one we did not test.