"redirect" outside embedded scope fails with unsafe navigation in Safari

I redirect to the managed pricing plan selection page using the recommended redirect pattern. This works fine in Chrome, and I think at one point it worked in Safari as well, but it no longer does for me. I’ve tried it with older versions of my app to see if it was. regression on my end, but this doesn’t seem to be the case. Looking at what happens in the code, it seems like everything happens as it should.

The issue seems to be that the redirect returns

<script data-api-key="{MY_API_KEY}" src="https://cdn.shopify.com/shopifycloud/app-bridge.js"></script>
<script>
window.open("https://admin.shopify.com/store/{MY_TEST_STORE}/charges/{MY_APP}/pricing_plans", "_top")
</script>

and Safari does not allow window.open to navigate from within the iframe, giving an error (removed some of the long URL for clarity:

[Error] Unsafe JavaScript attempt to initiate navigation for frame with URL 'https://admin.shopify.com/store/{MY_TEST_STORE}/apps/{MY_APP}l/app' from frame with URL '{MY_APP_URL}'. The frame attempting navigation of the top-level window is cross-origin or untrusted and the user has never interacted with the frame.

Any non-embedded redirect seems to fail. This is for a new app installation – perhaps relevant to the “user has never interacted with the frame” bit. I’ve filed an issue with shopify-app-js.

Is anyone else able to recreate this issue in Safari (I’m on version 18.6) with a new app install?

Doing the redirect client-side in an effect works fine (using open), by the way.

Do we think this is is shopify-app-bridge or shopify-js issue? (Or something else?

@_Ryan Same issue here, and for me it happens also in Chrome. Even for a non-js app, so I guess it’s related to the app bridge. It was working fine last thursday…

I’m not using managed pricing, but I’m getting the same error within the app loader function now when I request billing.

return billing.request({
  plan: MONTHLY_PLAN,
  isTest: process.env.NODE_ENV === "development",
});

@Lukas_Klappert @Phillip Thanks for chiming in. Nice to see it’s not just me. I’ve filed issues at the Shopify App Bridge and Shopify-App-Js repos. Seems to me a regression like this that impacts app installation ought to be a big priority to fix.

@Liam-Shopify Is this something the team is aware of? Seems like it could break installation/onboarding for any app that redirects outside the embedded scope, which I imagine is a lot of them, especially as that’s the preferred method in the docs!

I just found out we have the same problem. We don’t use the shopify template and at some point we had the same problem in safari, based on this old annotations:

[!warning]
The exit iframe script only works if you load app bridge,
Otherwise in safari it will show a security warning
see the script at “./src/templates/redirecting.html”

I don’t know what’s changed, but looking at the current app bridge code and the way the redirect is inserted, it seems like the window.open override happens asynchronously (after making some connection to the parent frame app bridge). Thus in the redirect the window.open is called before the app bridge is fully initialised and the window.open just uses the built-in version of that function, not the app bridge version.

It seems this ugly solution works:

const e = new URLSearchParams(location.search);
  const r = new URL(decodeURIComponent(e.get("exitIframe")));
  let attempts = 0;

  (function retryOpen() {
    const newW = open(r, "_top");
    attempts++;
    if (!newW && attempts < 20) {
      setTimeout(retryOpen, 300);
    }
  })();

I’m not sure how Shopify template works, so you have to see where it tries to redirect and just keep calling it until the window is created

Hi folks :waving_hand:

Sorry that you have run into this. This should now be resolved.

Please let us know if you continue to see issues.

1 Like

@Liz-Shopify I can confirm it’s working again for me, thanks!