All guides

Allow embedding on Vercel

If your page is blocked, the header comes from your vercel.json, your framework, or your code. Remove X-Frame-Options there and add a Content-Security-Policy header with frame-ancestors in the headers array of vercel.json.

3 min read · Updated

Find the header first

Run this against your production URL:

curl -sI https://your-site.com/ | grep -iE "x-frame-options|content-security-policy"

Then search your project for the source:

grep -Rni "x-frame-options\|frame-ancestors" vercel.json next.config.* middleware.* proxy.* src/ app/ 2>/dev/null

Common sources are a headers entry copied from a security template, a Next.js headers() function, and Helmet in an Express API.

Allow one partner site

Add or edit the headers array in vercel.json at the project root:

{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Content-Security-Policy",
          "value": "frame-ancestors 'self' https://partner.example"
        }
      ]
    }
  ]
}

Delete any X-Frame-Options entry from the same file. The source pattern /(.*) matches every path.

If you use Next.js, you can put the same header in next.config instead. Keep it in one place only. See Allow embedding in Next.js.

Allow framing on one path only

Lock the site and open one path:

{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "headers": [
    {
      "source": "/((?!embed/).*)",
      "headers": [{ "key": "Content-Security-Policy", "value": "frame-ancestors 'self'" }]
    },
    {
      "source": "/embed/(.*)",
      "headers": [
        { "key": "Content-Security-Policy", "value": "frame-ancestors https://partner.example" }
      ]
    }
  ]
}

The first rule skips paths that start with /embed/. This way, no path gets two CSP headers.

Check the result

Deploy, then check the production URL again with curl -sI. You want one CSP line with your frame-ancestors and no X-Frame-Options line.

Check a page that a function renders too, not only a static file. Your function code can set its own headers.

Common mistakes

  • Two CSP headers. Your app may send a CSP and vercel.json adds another. The browser enforces both, so the stricter one wins. Merge them into one policy.
  • A protected preview URL. Vercel can put preview deployments behind Vercel Authentication. Inside a frame, the visitor then sees a login page or nothing, not your app. Test on the production domain, or change Deployment Protection for previews.
  • ALLOW-FROM in X-Frame-Options. Browsers ignore it. Use frame-ancestors.
  • A CSP in a <meta> tag. frame-ancestors is ignored there. It must be a response header.

Test the deployment

Paste the production URL into the iframe tester. It shows if the page can load in a frame and what to change if not.

To check many pages at once, use the bulk check. It shows X-Frame-Options and frame-ancestors for up to 100 URLs.

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.