We are facing an issue where webhooks are not reliably registered in the development environment because npm run dev uses a temporary Cloudflare tunnel URL that changes on every restart. Shopify registers webhooks using the active tunnel URL at the time of registration; however, when the development server restarts, the URL changes and Shopify continues sending webhook events to the old, invalid URL. As a result, webhook events fail to reach the running application.
This issue does not occur in the production environment, where a permanent URL is used. A production deployment is therefore required to ensure stable, 24/7 webhook functionality.
We are developing a subscription-based app, and to test recurring order functionality, webhook registration is required. Is there any way to reliably register and test these webhooks in a development environment before deploying the changes to production?
This is a common bottleneck with the Shopify CLI. Because npm run dev generates a new tunnel URL every time it restarts, your webhook subscriptions end up pointing to old, invalid addresses on Shopify’s end.
To solve this, use a persistent tunnel. By setting up a static ngrok domain or a custom Cloudflare hostname, you can maintain a permanent URL. Launch the CLI with the tunnel-url flag followed by your static address. This ensures Shopify always knows exactly where to send events, even after you restart your local server.
Alternatively, list your webhooks in your shopify.app.toml file. The CLI will detect the new tunnel URL on startup and prompt you to update your app settings automatically.
For testing subscription logic specifically, you can also use the Shopify app webhook trigger command to bypass the tunnel and send mock payloads directly to your local endpoint.