iframe Refused to Connect: Why It Happens and How to Fix It

The grey "refused to connect" box means the page inside your iframe told the browser not to be framed. It does that with an X-Frame-Options response header (DENY or SAMEORIGIN) or a Content-Security-Policy frame-ancestors rule. Only the framed site's server can lift it. Paste its headers below to see which rule blocks you.

What each header value means for your iframe
Header on the framed pageWho may frame it
X-Frame-Options: DENYNobody, not even the same site
X-Frame-Options: SAMEORIGINOnly pages on the same origin
X-Frame-Options: ALLOW-FROM ...Obsolete, ignored by modern browsers
Content-Security-Policy: frame-ancestors 'none'Nobody
Content-Security-Policy: frame-ancestors 'self' https://a.exampleThe same origin plus the listed sites
Neither headerAnyone

Updated

This error is not a network failure and nothing is wrong with your iframe tag. The browser fetched the page, read a header that forbids framing, and replaced the content with an error. Clickjacking protection is the reason: a page that can be framed by anyone can be overlaid with invisible buttons. The fix depends on whose server sent the header.

Response header checker

Paste the response headers of the page inside the iframe. Everything runs in this page; nothing is fetched.

Response headers of the framed page

HTTP/2 200
content-type: text/html; charset=utf-8
x-frame-options: SAMEORIGIN
content-security-policy: default-src 'self'; frame-ancestors 'self' https://partner.example

Origin of the page that holds the iframe: https://shop.example

Origin of the framed page: https://docs.example

Restore the sample headers

Verdict: The browser will refuse to show this page in the iframe.

Server fixes you can copy

Each example allows the same site plus one partner. Replace https://partner.example with the origin that should be able to frame you, or use 'none' to block everyone.

nginx

always keeps the header on error pages too. Remove any older X-Frame-Options line so the two rules do not drift apart.

add_header Content-Security-Policy "frame-ancestors 'self' https://partner.example" always;

Apache (.htaccess or virtual host)

Needs mod_headers. Header always set replaces any earlier value of the same header.

Header always set Content-Security-Policy "frame-ancestors 'self' https://partner.example"

Express with Helmet

Helmet sets X-Frame-Options to SAMEORIGIN by default. Turning that off and setting frame-ancestors keeps one source of truth.

import express from "express";
import helmet from "helmet";

const app = express();
app.use(
  helmet({
    xFrameOptions: false,
    contentSecurityPolicy: {
      directives: { frameAncestors: ["'self'", "https://partner.example"] },
    },
  }),
);

Next.js (next.config.js)

headers() adds response headers to every matching route. Hosting platforms may add their own, so check the live response afterwards.

module.exports = {
  async headers() {
    return [
      {
        source: "/:path*",
        headers: [
          { key: "Content-Security-Policy", value: "frame-ancestors 'self' https://partner.example" },
        ],
      },
    ];
  },
};

Read the header, not the error

Browsers show the same grey box whichever rule fired, but the console names it. Look for a message mentioning X-Frame-Options or frame-ancestors, then open the Network panel to see the exact value the server sent.

Redirects matter too. If the iframe's address redirects to a login page, the header that counts is on the final response, which is often stricter than the page you expected.

Fixing it on a server you control

Decide who should be allowed to frame the page, then express that once, ideally as a frame-ancestors directive in your Content-Security-Policy. If a framework or security middleware adds X-Frame-Options by default, change its setting rather than adding a second conflicting header.

After deploying, clear any CDN cache and check the live response headers again, because many hosts add their own security headers at the edge.

When it is not your site

A site that blocks framing has decided it does not want to appear inside other pages. A link, a screenshot with a link, or the site's own embed widget are the honest alternatives.

Proxying another site's pages through your server to strip the header usually breaks its logins and may break its terms of use, so it is not a fix worth shipping.

How it works

  1. Open the page you want to frame in a normal tab, open the developer tools, and select the document request in the Network panel.
  2. Copy its response headers and paste them into the checker, or edit the sample that is already there.
  3. Enter the origin of the page that holds the iframe. The checker applies the same rules the browser uses and names the header that decides.
  4. If it is your own server, copy the matching fix from the server examples. If it is someone else's site, link to it instead of framing it.

Tips

Frequently asked questions

Can I bypass refused to connect from my own page?

No. The rule is enforced by the visitor's browser on behalf of the framed site, and no attribute on your iframe can override it. The only routes are changing the framed site's headers, using an embed URL the site provides for framing, or linking out.

Why does my own site refuse to load in its own iframe?

Check for X-Frame-Options: DENY, or frame-ancestors 'none'. Both block every parent, including pages on the same domain. Switch to SAMEORIGIN or frame-ancestors 'self'. Remember that a different subdomain or port is a different origin.

Should I use X-Frame-Options or frame-ancestors?

Use frame-ancestors, because it can list several allowed parents and wins whenever both are present. If you also send X-Frame-Options, keep it consistent with the CSP rule so the next person reading the config is not misled.

Why does a video or map link refuse to connect?

The ordinary watch or place page usually sends a framing header, while the service publishes a separate embed address meant for iframes, often found under Share then Embed. Our embed code generator converts supported links into those embed addresses for you.

Does frame-ancestors check every parent frame?

Yes. If your iframe sits inside another iframe, every ancestor up to the top page must match the policy, not only the direct parent.

Related: iframe sandbox tokens, iframe generator, Embed code generator, HTML iframe and video guide, CORS explained.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap