I’m encountering an issue when using Shopify CLI to run my app in development.
I’m building a Shopify app with the Node + Express template, which includes a checkout extension that needs to make network requests. Since checkout extensions run in a web worker, Shopify’s documentation states that I must return Access-Control-Allow-Origin: * in the preflight response headers to allow CORS.
However, when I start my server using shopify app dev (which sets up a Cloudflare tunnel), the Access-Control-Allow-Origin: * header is stripped from the preflight response, causing CORS to fail.
In contrast, when I run my Express server manually and set up an ngrok tunnel myself (without using Shopify CLI), this issue does not occur.
Response when using Shopify CLI (Cloudflare tunnel):
As shown above, the first response comes from Cloudflare, which appears to be the cause of the issue.
Some may suggest using the --tunnel-url flag to pass my manually created ngrok URL to the CLI, as mentioned in the documentation. However, I tried this, and the issue persists. It seems that Shopify CLI, regardless of whether it uses Cloudflare or ngrok, modifies the tunnel setup in a way that prevents the required CORS headers from being returned.
To clarify: Manually setting up an ngrok tunnel works without issue. Using Shopify CLI to tunnel (with both Cloudflare and ngrok) causes CORS to fail.
Has anyone encountered this before, or found a workaround?
Unfortunately, I did not find a solution. I ended up testing changes by the manual method I explained above. Everything ends up working end-to-end in production.
I opened a PR for this because I believe the issue is in Shopify CLI itself:
The shopify app dev reverse proxy seems to swallow or mishandle CORS preflight OPTIONS requests. Those requests never reach the local backend, so the app cannot return its own CORS headers. The browser then blocks the actual request.
That explains why:
the same backend works with a manually managed tunnel
it fails through shopify app dev
production can still work fine
I documented the repro here:
The PR fixes this by handling preflight requests directly in the CLI reverse proxy. If others here are seeing the same behavior, confirmation on the GitHub issue/PR would be helpful.