Checkout UI Extension and App Proxy

Hello everyone,

I’m developing a Checkout UI Extension that needs to fetch a json configurations from my backend server through a Shopify app
proxy. However, I’m encountering a persistent CORS error that I cannot resolve. I’ve read that this can be caused by a password protection issue, but I’m unsure how that would be fair to people who do not have access to a Live Shopify Plus subscription and or Paid Partner Plus sandbox site. Im using a Partner Development site with correct config.
(ive changed variables to obfuscate so might be wrong here)

The Error:

Access to fetch at

'https://store-worki1.myshopify.com/apps/app-dev-proxy/endpoint?foo=quick&operation=GET_SOMETHING' from     
origin 'https://extensions.shopifycdn.com' has been blocked by CORS policy: Response to preflight request doesn't pass access       
control check: Redirect is not allowed for a preflight request.

My Setup:

Checkout Extension Code (Checkout.tsx):

const { shop } = useApi();
const sessionToken = useSessionToken();
const checkoutToken = useCheckoutToken();
const shopDomain = shop.myshopifyDomain!;

const PROXY_BASE_URL = useMemo(() =>
  `${shop.storefrontUrl}/apps/app-dev-proxy`,
  []
);

... 
  const currentSessionToken = await sessionToken.get();
  const currentCheckoutToken = checkoutToken;
  // Making the request
  const [quickResponse, enhancedResponse] = await Promise.all([
    fetch(`${PROXY_BASE_URL}/endpoint?foo=quick&operation=GET_SOMETHING`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${currentSessionToken}`,
      }
    }),
    fetch(`${PROXY_BASE_URL}/endpoint?foo=enhanced&operation=GET_SOMETHING`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${currentSessionToken}`,
      }
    })
  ]);

App Proxy Configuration:

shopify.app.dev-1.toml:

[app_proxy]
url = "https://ngrok-ngrok-wombat.ngrok-free.app/api/proxy"
subpath = "app-dev-proxy"
prefix = "apps"

shopify.extension.toml:

[extensions.capabilities]
api_access = true
network_access = true

Backend Route (api.proxy.endpoint.tsx):

export const loader = async ({ request }: LoaderFunctionArgs) => {
    logRequestContext(request, { handler: 'loader' });
    const { admin } = await authenticate.public.appProxy(request);
    const { sessionToken, cors } = await authenticate.public.checkout(request);


    // Handle CORS preflight OPTIONS request
    if (request.method === 'OPTIONS') {
        return cors(new Response(null, { status: 200 }));
    }

    ....

    return cors(Response.json(
        {
            success: true,
            data: foo,
            operation: 'GET_FOO',
            source: configSource,
            fooType: finalfooType,
            shopDomain: shopDomain
        },
        { status: 200 }
    ));

What I’ve Tried:

  • Proper CORS headers in OPTIONS preflight handling
  • Using absolute URLs instead of relative paths
  • Both authenticate.public.appProxy() and authenticate.public.checkout() authentication
  • Verified app proxy configuration in Shopify admin
  • Added cors() wrapper to all responses

The Issue:

The error specifically mentions “Redirect is not allowed for a preflight request”, which suggests that somewhere in the request
chain, there’s a redirect happening during the OPTIONS preflight request that browsers don’t allow. I have logging in my remix file but it cant even reach it.

Questions:

  1. I seen a thread about possibility that the error may appear if your shop is password protected on the frontend, if this is the case how would I be able to bypass this when using a Partner Development store with Shopify Plus? I need the shopify plus features for the purpose of my extension.
  2. Is there a known issue with app proxies and Checkout UI Extensions causing redirects during CORS preflight?
  3. Should I be using a different URL structure for checkout extensions vs regular storefront requests?
  4. Is there a specific way to configure Remix routes to handle app proxy requests from checkout extensions without redirects?

Working Alternative:

When I bypass the app proxy and use a direct external URL (which I don’t want to expose), the requests work perfectly. This
confirms the issue is specifically with the app proxy handling of checkout extension requests.

Any guidance would be greatly appreciated! This seems to be a common issue but I haven’t found a definitive solution.

Environment:

  • Shopify CLI: Latest
  • App: Checkout and account UI extensions are enabled
  • Store: Checkout and Customer Accounts Extensibility feature enabled. But password protected since not a sandbox.
  • Remix: Latest
  • Checkout UI Extensions: 2025-07

Hi,

The error you’re seeing (Redirect is not allowed for a preflight request) happens because the OPTIONS preflight request is being redirected by Shopify before it reaches your app proxy. This usually occurs when the storefront is password protected, since Shopify automatically redirects all unauthenticated requests to /password.

That means your preflight requests never reach your Remix route, which explains why your logging doesn’t fire.

What to do:

Disable the storefront password while testing on your Partner Development store. This removes the redirect and allows preflight + CORS handling to work correctly.

Make sure your proxy calls are targeting the myshopify.com domain (https://{shop}.myshopify.com/apps/app-dev-proxy), not the storefront URL, to avoid hitting the password wall.

Your Remix CORS handler looks correct — the issue is Shopify intercepting before your app sees the request.

Using a direct external URL works because it bypasses the password gate, which confirms the proxy setup itself is fine.

In short: this isn’t a Checkout UI Extension issue, it’s the storefront password protection interfering with app proxy requests. Disabling the password (or testing on a Plus sandbox/live store without it) is the fix

let me know