Questions on Shopify embedded app as iframe

Topic summary

Main issue: An embedded Shopify app loads its UI from an external page via a server-side redirect in a Remix loader, which returns a page with a Content-Security-Policy (CSP) frame-ancestors header allowing admin.shopify.com and the merchant’s store. This works for framing, but prevents the Shopify admin navigation menu (ui-nav-menu) from rendering because the redirect bypasses the React component tree.

Key questions:

  • Is redirecting from the Remix loader to an external app (served with CSP frame-ancestors) the recommended pattern for an embedded app, or is there a better approach?
  • Can the Shopify admin menu be displayed while the main content is an external iframe? Specifically, can menu clicks execute logic to manipulate the iframe (without rendering additional UI), or are server-side redirects/iframes and admin menu rendering mutually exclusive?

Technical context:

  • Remix loader = server-side route handler executed before rendering.
  • CSP frame-ancestors = controls which origins can embed a page in an iframe.
  • Embedded app = app UI shown inside Shopify Admin via iframe.

Latest update: No answer yet; a follow-up asks if a solution was found. Status: Unresolved; open questions remain about recommended embedding strategy and preserving Shopify admin navigation with an external iframe.

Summarized with AI on December 25. AI used: gpt-5.

I have a few questions concerning iframe-ing an external web page for a Shopify app in the Shopify admin.

I have the Shopify app functionality housed in an external web page, say https://mysite.com/myapp/myapppage.html

In the Shopify remix app I am doing a redirect in the app/routes/app._index.jsx as follows:

export const loader = async ({ request }) => {
    ...

    return redirect("https://mysite.com/api/redirect");
}

The redirect is to an API that fetches the page at https://mysite.com/myapp/myapppage.html that dynamically adds the required Content-Security-Policy header for frame-ancestors,

e.g. frame-ancestors https://merchantstore.myshopify.com https://admin.shopify.com

This all works but my first question is:

Is this the right method to achieve the external web app in the Shopify admin as an embedded iframe app
or is there a better/recommended method? If so, what is that recommended method?

My second question is around the Shopify embedded app menu items.
For example, say I’d like to have the following menu in the Shopify admin:

I know this is simply implemented with the following in the app/routes/app.jsx file as:

export default function App() {
  const { apiKey } = useLoaderData();

  return (
    <AppProvider isEmbeddedApp apiKey={apiKey}>
      <ui-nav-menu>
        <Link to="/app" rel="home">
          Home
        </Link>
        <Link to="/app/Dashboard">Dashboard</Link>
        <Link to="/app/Products">Products</Link>
        <Link to="/app/Orders">Orders</Link>
        {/* Add this line */}
      </ui-nav-menu>
      <Outlet />
    </AppProvider>
  );
}

What I’d like to do is when the user clicks on the various menu items, have my app react to the selection and display the required content/data/etc.

Because of the redirect, however, this menu does not appear. As I understand it, because the redirect happened on the server side, the construction of the menu items is bypassed. If I remove the redirect, the menu items of course appear as expected.

Is there a way to have the Shopify admin menu items appear and do the redirect to my external app page and on clicks of the menu items not return/display any UI but just have logic executed to manipulate the iframed web app?

Or is it the case that once you do a redirect there cannot be any admin menu items displayed, i.e. redirect/iframing and Shopify admin menu items are
mutually exclusive

Many thanks in advance!

Did you figure this out?