IFrame Embedding Checker

Free online iframe checker: enter any webpage URL to inspect its X-Frame-Options and Content-Security-Policy frame-ancestors headers, find out whether the page can be embedded in an iframe, and confirm with a live preview. History is kept for the current browser session.

IFrame embedding check

:

Runs each line through the same header check and adds it to the session history below. Limited to 20 URLs per batch, checked a few at a time to be considerate to the target sites.

Checked: /
URL Result HTTP

Live preview

Header inspection is a fast first pass, but it cannot see JavaScript frame-busting: if the headers say "Embeddable" yet the preview stays blank, breaks out, or shows an error page, the page is not safely embeddable. The live preview is the final word.

History (this session)

Saved in this tab only (sessionStorage); cleared when you close the tab. Nothing is sent to the server.

No checks yet in this session.

How the check works

  1. Enter the target URL and click Check. The server fetches the page as a real iframe request (with Sec-Fetch-Dest: iframe) and reads its response headers.
  2. The verdict is derived from X-Frame-Options (DENY / SAMEORIGIN block framing) and Content-Security-Policy frame-ancestors (only * or a scheme wildcard allows arbitrary third-party parents).
  3. The same URL is loaded in the live preview iframe so you can confirm what the browser actually does, including JavaScript frame-busting that headers cannot reveal.

What determines whether a page can be embedded?

Whether a webpage can be shown inside an <iframe> on another site is decided by the browser, based on response headers sent by the page itself. This checker performs the same inspection server-side and gives you an immediate verdict.

X-Frame-Options is the classic header: DENY forbids framing on every page, SAMEORIGIN only allows pages from the same origin to frame it, and ALLOW-FROM has been removed from modern browsers. When the header is absent, legacy rules do not block framing.

Content-Security-Policy frame-ancestors is the modern replacement. It lists the origins allowed to embed the page — for example frame-ancestors 'self' https://example.com. A value of * (or a bare scheme such as https:) permits any HTTPS parent; anything narrower blocks third-party embedding.

Headers are not the whole story: page scripts can run frame-busting code (comparing top !== self and forcing a top-level navigation), and login pages or geo-restricted endpoints may behave differently for datacenter requests. That is why every result is paired with a live preview.

Quick guide: response header setup

If you own the site, control framing directly through response headers.

Block embedding from any page

X-Frame-Options: DENY Content-Security-Policy: frame-ancestors 'none'

Browsers refuse to render the page in any iframe — the strictest clickjacking protection.

Allow same-origin embedding only

X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self'

Only pages with the same scheme, host, and port may frame it; third-party sites are blocked.

Allow specific origins only

Content-Security-Policy: frame-ancestors 'self' https://trusted.example.com

List trusted origins in frame-ancestors; origins not listed are blocked.

Allow embedding from any page

Do not set X-Frame-Options Content-Security-Policy: frame-ancestors *

Any site can frame the page in an iframe. Evaluate the security trade-off.

Note: X-Frame-Options is superseded by CSP frame-ancestors. When both are present, CSP wins — prefer frame-ancestors.

How does the server detect a request comes from an iframe?

Since around 2020, Chromium- and Firefox-based browsers automatically attach a set of Fetch Metadata request headers to every navigation and subresource request. The most useful one for framing checks is Sec-Fetch-Dest — it tells the server what kind of context requested the resource, without any cooperation from the requesting page.

  • Sec-Fetch-Dest: document — top-level navigation, not inside any frame.
  • Sec-Fetch-Dest: iframe — the request is loaded inside an <iframe> element.
  • Sec-Fetch-Dest: frame — loaded inside a legacy <frame> (frameset).
  • Sec-Fetch-Dest: embed / object — loaded inside an <embed> or <object> element.

This checker sends its own probe with Sec-Fetch-Dest: iframe, mirroring exactly what a real browser sends when embedding a page — so the verdict reflects how the target server actually behaves for genuine iframe requests, not just a generic fetch.

Sec-Fetch-Dest is a useful signal but not a security boundary: it is only sent by modern browsers, and non-browser clients — curl, bots, some webviews and older browsers — can omit it entirely or send an arbitrary value. A server should log or rate-limit based on it, but never rely on it alone to decide whether framing is safe; that decision still belongs to X-Frame-Options and CSP frame-ancestors, which browsers enforce independently of request headers.

On the client side, a page can also detect that it is running inside a frame without any header, e.g. by comparing window.top !== window.self (or reading window.frameElement for same-origin frames), then react — show a warning, or force a top-level redirect. That is the frame-busting technique mentioned earlier, and it works regardless of what the request headers said.

Server config examples: block iframe embedding

The snippets below show how to configure each server or framework to block iframe embedding entirely (X-Frame-Options: DENY + CSP frame-ancestors 'none') — the strictest of the recipes from the quick guide above.

server {
    location / {
        add_header X-Frame-Options "DENY" always;
        add_header Content-Security-Policy "frame-ancestors 'none'" always;
    }
}
<IfModule mod_headers.c>
    Header always set X-Frame-Options "DENY"
    Header always set Content-Security-Policy "frame-ancestors 'none'"
</IfModule>
app.use((req, res, next) => {
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
  next();
});
// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          { key: 'X-Frame-Options', value: 'DENY' },
          { key: 'Content-Security-Policy', value: "frame-ancestors 'none'" },
        ],
      },
    ];
  },
};
class SetFrameOptions
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);
        $response->headers->set('X-Frame-Options', 'DENY');
        $response->headers->set('Content-Security-Policy', "frame-ancestors 'none'");

        return $response;
    }
}
export default {
  async fetch(request) {
    const response = await fetch(request);
    const headers = new Headers(response.headers);
    headers.set('X-Frame-Options', 'DENY');
    headers.set('Content-Security-Policy', "frame-ancestors 'none'");
    return new Response(response.body, { status: response.status, headers });
  },
};

Only need to allow your own site, or a short allow-list, to frame the page instead of blocking everyone? Swap DENY for SAMEORIGIN, and 'none' for 'self' or an explicit list of origins — the rest of the configuration stays the same.

Known platform gotchas

General header rules aside, some well-known platforms have their own quirks — worth knowing before you assume "blocked" or "embeddable" from headers alone.

Platform / scenario Behavior Why
YouTube watch page (youtube.com/watch) Blocked Use the official youtube.com/embed/{id} player URL instead — the normal watch page sends a restrictive framing policy.
Google Maps place page Blocked Only the Maps Embed API iframe URL (google.com/maps/embed) is meant to be framed.
Google / Microsoft OAuth login pages Blocked Deliberately blocked since 2015 to stop credential-phishing inside iframes; the login flow must run in a top-level window or popup.
Payment checkout pages (Stripe Checkout, PayPal, most bank gateways) Blocked Framing a payment form is a classic clickjacking vector, so processors refuse it outright.
GitHub repository / file pages Blocked Site-wide frame-ancestors 'none'; use the REST/GraphQL API or a screenshot instead of an iframe.
Notion / Google Docs "Publish to web" pages Embeddable Explicitly designed to be embedded, and the product provides ready-made embed code.
Wikipedia articles Embeddable No restrictive X-Frame-Options/CSP by default, but check the licensing and attribution terms before embedding at scale.

Common use cases

  • Decide whether a third-party widget, dashboard, or document can be embedded in your own product before writing integration code.
  • Verify that your own site sends the X-Frame-Options or CSP frame-ancestors policy you intended.
  • Debug clickjacking protection: understand why a page shows about:blank or a refusal message inside an iframe.
  • Batch-screen candidate URLs during content aggregation or portal integration, using the session history to revisit results.
  • Prepare for security reviews or penetration tests by documenting the framing policy of external dependencies.

FAQs

Why does a page reported as "Embeddable" stay blank in the preview?
Response headers allow framing, but the page likely contains JavaScript frame-busting, requires login or cookies, or serves different content based on the visitor. Trust the preview.
Can I bypass X-Frame-Options or CSP?
No. These headers are enforced by the browser for security (clickjacking protection); client-side workarounds are unreliable. To embed content you do not control, ask the site owner to allowlist your origin in frame-ancestors, or use an official embed/API solution they provide.
What is the difference between DENY and SAMEORIGIN?
DENY blocks the page in every iframe, including same-origin pages; SAMEORIGIN permits framing only by pages from the same scheme, host, and port.
Does the checker store my URLs?
History lives only in your own browser tab via sessionStorage and disappears when the tab closes. The check server only fetches the requested URL to read its response headers.
Why does the same URL give different results at different times?
Sites may send different headers per path, after redirects, by User-Agent, or based on A/B experiments and WAF rules. Re-run the check to get the current state.