Monitor a Shopify App You Built: Webhooks and OAuth
The quick version: To monitor a Shopify app you built, run a no-code API monitor on your webhook receiver and a second one on your app's API surface, from multiple regions, because a browser monitor cannot script the per-shop install flow. Shopify gives your webhook receiver a one-second connection timeout and a five-second total budget, and only a 200 counts as an acknowledgement. Miss that window and Shopify retries a failed webhook 8 times over roughly 4 hours, then keeps going on its own schedule while your deliveries quietly drop on the floor. Shopify never pages you about it, and it publishes no uptime SLA for your app, so the merchant who built a workflow on your app finds out first, then tells you. Velprove probes the endpoints Shopify will hit and the fields your app depends on from 5 regions, free to start and no-code to set up. It does not complete the Shopify OAuth or install consent, because that is a per-shop, merchant-authenticated grant no synthetic login can replay.
Are you the merchant, or the developer who built the app?
First, make sure you are on the right page. If you run a Shopify business and you are worried about whether buyers can complete a purchase, you want the merchant guides, not this one. Start with how to monitor your Shopify store uptime for the front-of-house reachability angle, and monitoring the checkout path for the buy-side flow. Both of those, plus the segment overview at Velprove for Shopify, are written for the person running the storefront.
This post is for the other person. You built an embedded Shopify admin app and the webhook consumers behind it. You own a receiver that Shopify POSTs to, an API surface your app calls, and an OAuth install flow each merchant runs once. None of that shows up on a storefront status page, and none of it is covered by a merchant uptime check. When your app breaks, it breaks in a place only you are responsible for, and the platform that hosts you will not tell you it happened.
What actually breaks in an app you built (and Shopify never tells you)
Two surfaces in an app you built fail silently, and both of them sit outside anything Shopify reports on your behalf.
The first is your webhook receiver. Shopify sends a topic like an order creation or an app uninstall as an HTTPS POST to a URL you registered. If that URL starts answering slowly, returning a redirect, throwing a 500, or rejecting valid signatures after a deploy, Shopify treats the delivery as failed and moves into a retry path. From the outside your process looks alive. The web server is up, the health check is green, and yet the deliveries that drive your app are not landing.
The second is your app's own API surface, the calls your embedded admin UI makes and the Admin API requests your backend issues. A schema change, a rotated credential, or a retired API version can change what comes back without changing the status code. The page renders, the request returns 200, and a field your code relied on is suddenly missing or shaped differently.
Here is the uncomfortable part: Shopify does not publish a numeric uptime SLA for your app. It reviews you for things like HMAC verification of webhooks and for performance, including a guideline that your app should not drop Lighthouse performance scores by more than ten points, but it does not promise or measure your availability for you. Reachability after you go live is your problem. The stakes are not abstract: when a delivery silently fails, the merchant who depends on that automation usually notices before you do, and you hear about your own outage as a support ticket. Monitoring exists to flip that order.
How Shopify delivers webhooks: the 5-second budget
The webhook mechanics are documented precisely, and they are the spine of the whole monitoring argument. Shopify's HTTPS webhook delivery documentation spells out the timing your receiver lives inside.
Shopify delivers each webhook as an HTTPS POST. It allows a one-second connection timeout and a five-second timeout for the entire request. The only response that counts as a successful acknowledgement is a 200. Anything outside the 200 range is treated as an error, and that explicitly includes 3xx redirects. A receiver that 302s to a canonical host, or sits behind a redirect you forgot about, is failing every delivery even though a browser would follow the redirect without complaint.
When Shopify receives no response or an error, it retries 8 times over the next 4 hours. Those are the real numbers; do not round them up to a week of retries or a different count. During those four hours your deliveries are queued and re-attempted, which means a receiver that is slow or erroring is dropping real events the entire time, not just at the moment it broke.
There is a deletion consequence, but it is narrower than the scary version you have probably heard. After 8 consecutive failures, Shopify automatically deletes the subscription only if it was configured using the Admin API, meaning a shop-specific subscription. App-specific subscriptions declared in your app configuration are not deleted by Shopify. So the blanket claim that Shopify deletes your webhook after failures is wrong for config-declared subscriptions, and you should not repeat it. The thing that is always true, regardless of subscription type, is that during the failure window deliveries are not being processed by your app, and the first human to notice is usually the merchant, not you.
Why HMAC verification makes your receiver fragile
Every Shopify webhook arrives signed, and the signature is where a lot of receivers quietly break. Each HTTPS delivery includes a base64-encoded signature in the X-Shopify-Hmac-Sha256 header. Your handler is expected to recompute it: take the HMAC-SHA256 of the raw request body using your app's client secret, base64-encode the result, and compare it against the header value with a constant-time comparison. If they match, the delivery genuinely came from Shopify. If they do not, the correct response is a 401.
The fragility is in the details. The HMAC must be computed over the raw, unparsed body, which means any body-parsing middleware that runs before verification corrupts the bytes and breaks the comparison. The secret is your app client secret, also called the API secret key, not an access token and not a separate signing key, so a credential rotation that updates one place and not the other turns every valid delivery into a rejected one. A subtle bug here does not crash your app. It turns a healthy-looking endpoint into a silent 401 machine that Shopify reads as a string of failures.
This is also why the compliance side matters. Every app distributed through the Shopify App Store must answer the mandatory compliance webhooks, customers/data_request, customers/redact, and shop/redact, even if your app stores no customer data. Those handlers are held to the same bar: acknowledge with a 200-series status, return 401 on a bad HMAC. They are real routes that must stay alive, so they belong in your monitoring too. Shopify webhook HMAC signing is its own scheme, separate from how other providers sign; if you also handle Stripe webhook signatures, the idea is similar but the header names and retry behavior differ, so do not assume one verifier covers both.
For monitoring, the honest boundary is this. A monitor cannot stand in for your HMAC verifier, and it should not pretend to. What it can do is confirm the endpoint Shopify will hit is answering correctly and fast enough, on a route you control, which is the next section.
Monitor the webhook receiver: assert 200 inside Shopify's window
The right tool for the receiver is an API monitor that calls the endpoint Shopify will call and asserts on what comes back. Velprove probes the endpoint from five regions and checks the things that map directly to Shopify's delivery rules.
Point the monitor at a health or canary route on your receiver, not at a real webhook topic that mutates data, and assert three things. Assert the status code equals 200, because that is the only response Shopify accepts and the only one that proves your route is the live handler rather than a stale page or a redirect. Assert the response time is under a threshold you tune below Shopify's five-second total budget, so you find out the receiver is getting slow before it starts timing out under real load. Assert a body marker or a response header you control, so a 200 from a generic 404 page or a load-balancer splash does not pass as healthy.
Velprove can assert on the body content of the response, for example that a known marker string is present or that an error string is absent, and it can assert on the response headers your endpoint returns. That header assertion is useful for confirming your receiver answers with the headers you expect, for instance a content type or a custom marker header you set on the health route. To be precise about the boundary: Velprove asserts on the values your endpoint returns. It does not compute or send a valid X-Shopify-Hmac-Sha256 signature, and it does not deliver a signed test payload your verifier would accept. It probes the route and checks the answer.
Two limits to be honest about. Velprove does not receive inbound webhooks; there is no passive receiver waiting for Shopify to POST to Velprove, so it cannot confirm a real delivery landed. It probes the endpoint that Shopify will hit, on your schedule, from the outside. And if you want to chain calls, for instance fetch a token on one step and reuse it on the next, that is a multi-step pattern. The mechanics of chaining requests and extracting values between steps are covered in our multi-step API monitoring guide, and the same engine drives a single receiver probe. The receiver check itself is often a one-step monitor.
Your app breaks quietly when an API version retires
The receiver is one silent-failure surface. The API version your app targets is the other. Shopify releases a new API version every three months at the start of the quarter, named by date in the YYYY-MM form, for example 2026-04. Each stable version is supported for a minimum of twelve months, with at least nine months of overlap between consecutive versions, so you get a generous window. The trap is what happens when that window closes.
Retirement is not a 404. If your app targets a version that is no longer accessible, Shopify falls forward and responds using the oldest accessible stable version. Your request still succeeds, still returns a 200, and now carries a newer serialization of the data, with fields renamed, removed, or reshaped. This is schema drift, not an endpoint disappearing, and it is exactly the kind of break a status check sails right past.
Monitor it the same way you would monitor any data contract you depend on. Point a monitor at a representative call into your own app's surface and assert on the response shape, not just the status. Assert that a field you genuinely rely on is present and not null, so the day the serialization changes and that field goes missing, the monitor fails instead of your customers. If part of your surface is GraphQL, remember that a 200 can still carry a populated GraphQL errors array even when the transport looks fine; that post covers the errors-array assertion in full, so this one will not repeat it.
The honest limit: why a browser-login monitor can't watch your install flow
There is a real limit worth stating plainly, because it shapes which tool you reach for. You cannot point a synthetic browser-login monitor at your app's install or OAuth flow and have it complete the install.
Completing a Shopify app install requires an interactive consent screen that Shopify renders inside a specific shop's admin, where an authenticated merchant deliberately clicks to grant your app the access scopes it asked for. That screen is per-shop and merchant-authenticated. There is no static, replayable login that a monitor owns, because the thing being authenticated is a particular merchant's session in a particular store, not a generic test account on your app's own domain. A browser monitor that fills a username and password into a login form cannot manufacture that consent. This is the same class of limit that applies to OAuth and SSO logins that are not a plain email and password: when the credential is a delegated, interactive grant, a form-fill monitor has nothing to fill.
It helps to know how modern embedded apps actually authenticate, so you scope the limit correctly. An embedded admin app authenticates the merchant's in-admin session with App Bridge and short-lived session tokens, which are JWTs with a one-minute lifetime, and exchanges those for API access tokens via token exchange. Shopify now recommends managed installation plus token exchange for embedded apps, so they no longer need to implement the authorization code grant for installation. That grant is not deprecated or removed across the platform, though; standalone apps still use it. The takeaway is narrow and important: the install and OAuth consent step is what a browser monitor cannot script. It does not mean you cannot monitor anything about your Shopify app. Your webhook receiver, your API surface, and much of your app's own backend are all monitorable with API and multi-step monitors.
What Velprove can and cannot assert for your Shopify app
Keeping the boundary explicit saves you from building a monitor on a wrong assumption. Here is the honest split.
Velprove can probe your webhook receiver and your app API endpoints from five regions. It can assert on the status code, on the response time against a threshold, on the response body content with present-or-absent string checks, and on the response headers your endpoint returns. It can chain multiple API calls in a multi-step monitor and extract a value from one step to reuse in the next. It can run a browser-login monitor against your app's own login surface if your app exposes a plain username-and-password login form of its own, with one success indicator.
Velprove cannot receive an inbound webhook, because there is no passive receiver on Velprove's side waiting for Shopify to POST to it. It cannot compute or send a valid Shopify HMAC-signed payload as a signing step, because it asserts on returned values rather than acting as a request-signing engine. It cannot complete the interactive, per-shop OAuth or install consent. It cannot read a merchant's inbox or click a magic link. And it does not judge the semantic quality of a response; it checks shape, latency, status, headers, and body content, not whether the data is business-correct. If you need the same generic pattern for a non-Shopify dependency, the approach we describe for monitoring a payment gateway that is not Stripe uses the same probe-and-assert engine from five regions.
Set this up in Velprove (no code)
You can build both monitors in the wizard without writing any code. Velprove is free to start and no-code for the setup, and the receiver and version-shape monitors below both fit comfortably inside the free plan.
Build the webhook receiver monitor. Create an API monitor, point it at the health or canary route on your receiver, and add the three assertions from the receiver section: status code equals 200, response time under your tuned threshold, and a body or header marker that proves it is the live handler. Choose multiple regions so a partial or regional reachability problem is caught rather than masked by a single vantage point.
Build the version-shape monitor. Create a second monitor against a representative call into your own app's surface and assert that a field you depend on is present and not null. That is the monitor that catches the silent schema drift when an API version retires and Shopify falls forward to a newer serialization.
Wire alerting to wherever you already triage, and you have flipped the order: when your receiver slows past Shopify's budget, or a delivery path breaks, or a field you depend on quietly goes missing, you hear about it from your monitor instead of from the merchant who built their day around your app.
Start monitoring your Shopify app with Velprove. Free, no-code setup, five regions, commercial use allowed. Probe the endpoints Shopify will hit and the fields your app depends on, and find out before your merchants do.
Frequently asked questions
How long does my Shopify app have to respond to a webhook?
Shopify allows a one-second connection timeout and a five-second timeout for the entire request. Only a 200 response counts as an acknowledgement. Anything outside the 200 range, including 3xx redirects, is treated as a failure. If your receiver answers slowly, redirects, or returns a non-200 status, Shopify considers the delivery failed and enters its retry path.
Does Shopify really delete my webhook subscription after failures?
Only in one specific case. If Shopify receives no response or an error, it retries 8 times over the next 4 hours. After 8 consecutive failures, the subscription is automatically deleted only if it was configured using the Admin API, meaning a shop-specific subscription. App-specific subscriptions declared in your app configuration are not deleted by Shopify. Either way, deliveries are dropping during the failure window, which is the problem a monitor catches first.
Can Velprove verify my Shopify HMAC signature for me?
No. Velprove does not compute or send a Shopify HMAC-signed payload, and it is not a request-signing engine. What Velprove can do is probe the endpoint Shopify will hit and assert that it returns 200 within the five-second budget, plus assert on the response headers and body that the endpoint returns. Your own handler is responsible for verifying the X-Shopify-Hmac-Sha256 header over the raw request body with your app client secret.
Why can't a browser monitor sign into my app's Shopify install flow?
The install and OAuth consent step is an interactive, per-shop, merchant-authenticated screen that Shopify renders inside that store's admin. A synthetic browser monitor with a static test login cannot script it, because there is no replayable login that the monitor owns and the consent is a deliberate human action scoped to one shop. For install and OAuth coverage, the right tool is an API or webhook-endpoint monitor, not a browser-login monitor.
What happens to my app when a Shopify API version retires?
Shopify does not return a 404 for a retired version. It falls forward and responds using the oldest accessible stable version, so your code receives a newer serialization with changed or removed fields. The break is silent schema drift, not an endpoint disappearance. A monitor that asserts on the response shape, for example that a field you depend on is present and not null, catches the day the drift starts returning something your code did not expect.
Do I still need to monitor the mandatory compliance webhooks?
Yes. Every app distributed through the Shopify App Store must respond to the mandatory compliance webhooks, customers/data_request, customers/redact, and shop/redact, even if the app stores no customer data. They should acknowledge receipt with a 200-series status and return a 401 on an invalid HMAC. Those receiver routes are endpoints you must keep alive and answering, so they belong in your monitoring alongside your business webhooks.