Iframe not loading in Visual Editor when using Vercel Preview Deployment url

Builder content link

Builder public api key
f7525ed44d54419a91ab4f30a89d09a6

What are you trying to accomplish
I want to load a page on the Visual Editor but when I use a URL from Vercel Preview Deployment, the iframe doesn’t load. I tried using the Chrome Extension, using vercelPreview: true and setting nextjs headers to allow builder.io.
Here’s the error I am getting:
Refused to display ‘https://vercel.com/’ in a frame because it set ‘X-Frame-Options’ to ‘deny’.

Screenshots or video link
Video Link

Code stack you are integrating Builder with
NextJS

Reproducible code example

  const content = await builder
    // Get the page content from Builder with the specified options
    .get("page", {
      userAttributes: {
        // Use the page path specified in the URL to fetch the content
        urlPath: "/builder/" + (props?.params?.page?.join("/") || "")
      },
      options: {
        vercelPreview: true
      },
      // Set prerender to false to return JSON instead of HTML
      prerender: false
    })
    // Convert the result to a promise
    .toPromise();

Hey @elisamartins I tested my vercel preview on your space. It worked fine.
Could you test the following code for the integration:

const page = await builder.get('vercel', {
    userAttributes: {
      urlPath: '/' + (params?.page?.join('/') || ''),
    }
  })
  .toPromise() || null

Hello Scheema, thanks a lot for the reply ! I am still getting the same error. Do you have any special configuration for your Vercel environment ? I tried setting the X-Frame-Options headers in my next.config.js file like but it doesn’t work.

async headers() {
    return [
      {
        source: "/:path*",
        headers: [
          {
            key: "X-Frame-Options",
            value: "ALLOWALL"
          },
        ]
      }
    ];
  },

Could you please share your Builder content entry link with me?

I’m not sure what you mean. Is it this link: Builder.io: Visual Development Platform

Could you try with the below configuration and let me know how it goes?

async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          // this will allow site to be framed under builder.io for wysiwyg editing
          {
            key: 'Content-Security-Policy',
            value: 'frame-ancestors https://*.builder.io https://builder.io',
          },
        ],
      },
    ]
  },

Hi Scheema, unfortunately I am still getting the error “Refused to display ‘https://vercel.com/’ in a frame because it set ‘X-Frame-Options’ to ‘deny’.”

Hey @elisamartins I can see the issue is still not resolved. Please try to set X-Frame-Options header with the value ALLOW-FROM https://builder.io. Could you please install the Builder chrome extension and check whether you have the access to builder Component. If you have updated your Vercel configuration it might be a cache issue.

I’m having the same issue with my Vercel Preview environments.

I added the vercelPreview option like this

  const page =
    (await builder
      .get("page", {
        userAttributes: {
          urlPath: "/" + (params?.page?.join("/") || ""),
        },
        options: {
          vercelPreview: process.env.NEXT_PUBLIC_VERCEL_ENV	=== 'preview',
        }
      })
      .toPromise()) || null;

I also set the CSP frame-ancestor header and X-FRAME-OPTIONS (although this is superseded by the CSP as so

  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          // this will allow site to be framed under builder.io for wysiwyg editing
          {
            key: 'Content-Security-Policy',
            value: 'frame-ancestors https://*.builder.io https://builder.io',
          },
          {
            key: 'X-FRAME-OPTIONS',
            value: 'https://*.builder.io https://builder.io',
          },
        ],
      },
    ]
  },

I have the Builder Chrome extension and it has access to the builder Component.

This is what I see in the Builder Editor

My production Vercel deployment works as expected.

It appears that Vercel is throwing a 401 Unauthorized Error to Builder. I assume my user session isn’t being passed properly from my browser via the Builder editor to authenticate to my preview deployment.

Hey @spm922 please share your Builder content entry link with me to investigate the issue further.

I am having this exact same error. Same Next.js/Vercel config.

  • updated env variable NEXT_PUBLIC_BUILDER_API_KEY in my Vercel config. Same as what I am using for localhost (which works).

Using the below setting:
async headers() {
return [
{
source: ‘/:path*’,
headers: [
// this will allow site to be framed under builder.io for wysiwyg editing
{
key: “X-Frame-Options”,
value: “ALLOWALL”
},
],
},
]
}

  • Getting this set of 3 errors:
Failed to load resource: the server responded with a status of 401 ()

chrome-error://chromewebdata/:1 Refused to display 'https://vercel.com/' in a frame because it set 'X-Frame-Options' to 'deny'.
        
GET https://cdn.builder.codes/api/v1/proxy-api?url=... 401 (Unauthorized)

@sheema any ideas? Site deploys correctly.

Hey all, after spending hours trying to solve the same issue getting a 401 with the error “… in a frame because it set X-Frame-Options to deny.” I would like to share what worked for me.

Even after adding the frame-ancestors CSP header to my Next.js 14.2.7 app allowing https://builder.io I wasn’t able to render the page through the builder.io editor iframe and was getting still the same error.

What helped in the end (additionally to the CPS header) was implementing a " Protection Bypass for Automation" in the Vercel Project “Deployment protection” settings. This allows a request being sent to the application to bypass the Vercel authorization (which seems to be problematic through iframes) as well as the iframe protection. Have a look here for information on how to implement.

For me it was enough to add the bypass token as a query param to the preview URL in the builder.io editor.

Here are some other things that might be confusing when thrown together with the iframe issue:

  • Publishing the page can take a couple of minutes to an hour even so try to stick to one page path when working in the issue to isolate it
  • I was having issues with using the root path / for my page, so that might be another factor

TLDR: Try to use both the frame-ancestors CSP header as well as a Protection Bypass for Automation to be able to make requests to your Next.js app using an iframe