Embedding Your Site

By default, a site deployed on Maravilla can only be framed by Maravilla’s own surfaces — the Studio editor, which loads your site in an iframe for inline editing. Any other page that tries to embed it gets a blank frame and a console error.

To embed your site somewhere else — a Microsoft Teams tab, a SharePoint or intranet portal, a partner’s page, your own second domain — you name the embedding origin. There are three ways to do it, and all three are combined: whatever you set is added to Maravilla’s own list, never substituted for it. Widening this can admit a new surface; it can never break Studio editing.

The quickest way: set the header from your app

If your framework already lets you set response headers, you need no platform configuration at all. Send a Content-Security-Policy with the origins you want, and Maravilla merges them into the list it serves:

// SvelteKit — src/hooks.server.ts
export async function handle({ event, resolve }) {
  const response = await resolve(event);
  response.headers.set(
    'Content-Security-Policy',
    "frame-ancestors 'self' https://teams.microsoft.com https://*.teams.microsoft.com " +
      'https://teams.cloud.microsoft https://*.cloud.microsoft',
  );
  return response;
}

The rest of your policy is yours: script-src, object-src, anything else you send is passed through to the browser untouched. Only frame-ancestors is merged.

In your project config

If you would rather keep the allowlist in the repo — reviewable in a pull request, versioned with the code that needs it — declare it in maravilla.config.ts:

// maravilla.config.ts
export default {
  security: {
    frameAncestors: [
      'https://teams.microsoft.com',
      'https://*.cloud.microsoft',
    ],
  },
};

This takes effect on the next deployment.

In the console

For a change that should apply now, without a redeploy: open your project, go to Settings → Domains, and use the Embedding card. Add one origin per entry and save. It is live within a few seconds.

Use this when a partner needs to embed your site today, when you are testing an integration, or when the team that owns the embedding surface is not the team that owns the code.

What counts as a valid origin

Each entry is a Content-Security-Policy source:

ValueMeaning
https://teams.microsoft.comExactly that origin
https://*.cloud.microsoftAny single sub-label — teams.cloud.microsoft matches, a.b.cloud.microsoft does not
http://localhost:5173A local development origin
'self'Your own origin (already included)

Rejected, because a browser would silently drop the whole directive rather than tell you why:

  • a bare *
  • more than one wildcard label (https://*.*.example.com)
  • an origin with a path (https://example.com/embed)
  • a value with no scheme (teams.microsoft.com)

A host wildcard covers exactly one label. https://*.microsoft.com does not match https://teams.cloud.microsoft.com — name each host you actually need.

Troubleshooting

The frame is blank and the console says the page refused to connect. Read the error: it names the origin the browser saw. That is the value that has to be in your list — for a nested embed (a widget inside a client, inside a page) every ancestor origin must be named, not just the outermost one.

You set the header but the old list still arrives. Check that the response you are inspecting is the one your app produced. Requests that never reach your app — an error page, a request that was refused — carry Maravilla’s default list instead.

It works in curl but not in the browser. Send only one Content-Security-Policy header. A browser enforces every CSP header it receives and takes the intersection of them, so a second header can only narrow the policy, never widen it.