Did Shopify change the webhook retry policy?
Shopify shortened its webhook retry window on September 10, 2024. Every blog post older than that is now out of date. Here's what changed and what to update in your runbook.
Last reviewed · Verified against Shopify dev docs.
Did Shopify change the webhook retry policy?
What changed on September 10, 2024
The changelog entry is short. The relevant sentence:
Webhooks will now be retried a total of 8 times over 4 hours using an exponential backoff schedule.
Two practical consequences that aren't spelled out in the changelog but follow directly:
- Your full retry budget is shorter. A handler that's down for half a day no longer recovers on its own from the queue — the window closed.
- Subscription auto-removal triggers faster. The troubleshooting doc says it plainly: "Shopify retries failed webhook calls up to eight times in a four-hour period, but if failures persist past that point the webhook subscription is removed." Whatever your prior assumption was about how long you could be down before losing the subscription, halve it.
What the prior policy looked like
The exact prior values are not quoted on shopify.dev. They were widely community-documented as 19 retry attempts over 48 hours — that's what most blog posts still cite. Treat that as community recollection, not Shopify's words. The official record only documents the current policy and the date it took effect.
The deprecation of the longer window matters for two reasons:
- If you copy-pasted retry-aware logic from a 2022 or 2023 post, your backoff assumptions about when events become "permanently lost" are now too generous.
- SLA wording in your customer agreements that referenced "48-hour Shopify retry" is now technically incorrect.
The new X-Shopify-Triggered-At header
Shipped alongside the retry-window change. It carries the timestamp Shopify originally fired the event, regardless of how many retries it took to land. Useful when:
- Your handler does freshness-sensitive work (auto-cancel an unpaid order older than X minutes). A payload that took 3 hours to arrive should not trigger the cancel path.
- You want to chart end-to-end latency from Shopify's source-of-truth time to your ingest time, not your handler-receive time.
Example check before processing:
triggered = Time.iso8601(request.headers["X-Shopify-Triggered-At"])
if Time.now - triggered > 30.minutes
Rails.logger.warn("late delivery: #{Time.now - triggered}s")
# decide per-topic whether to skip stale logic
end
What this changes about how you should run webhooks
Runbooks
Any documented playbook that says "Shopify retries for 48 hours, so we have until tomorrow to fix the handler" is wrong. Cut every "X hours until permanent loss" estimate to a quarter of what it used to be. The realistic deadline is closer to 4 hours from the first failure for new events to keep arriving, and the same 4-hour clock decides whether your subscription survives.
Monitoring
If you alert on "no webhooks in N minutes," the threshold for N matters more now. Before the change you might have gone half a day before discovering something was wrong and still recovered. Now, by the time you've gone half a day, the subscription's gone and you're doing Admin API reconciliation instead of a simple replay.
Reconciliation cadence
Hourly Admin API reconciliation went from nice-to-have to load-bearing. Once the retry budget closes, the Admin API is the only source of truth for what Shopify actually recorded. Polling once a day means the longest gap between a missed event and recovery is 24 hours. Polling hourly caps it at an hour.
Quick audit checklist
Five things to check before this week's release:
- Search your codebase for any literal "48" or "19" near the word "retry" or "webhook." Update or delete.
- Check your customer-facing docs (status pages, support articles, SDK readmes) for the same. Customers cite your docs back to you in tickets — keep them honest.
- Confirm your monitoring alerts fire well inside the 4-hour window. A "no webhook in 6 hours" alert is now too late.
- Make sure something — a cron, a worker, a service — re-registers a webhook subscription that's been auto-removed. The 4-hour window doesn't reset when you fix the handler; it just stops sending.
- If you don't already reconcile against the Admin API, today's a good day to start. The retry window is too short to assume retries alone will save you.
Where HookRescue fits
We sit between Shopify and your handler. Failed deliveries get retried by us for 7 days instead of 4 hours, so transient outages stop ending in dropped events and removed subscriptions. We also re-register subscriptions when Shopify deletes them and pull from the Admin API hourly to backfill anything that slipped through. The September 2024 change made the recovery side of the equation more important, not less — we're built around it.
Related problems
- Shopify webhook not firing: debug checklist and recovery steps
- Shopify webhook subscription removed: causes, detection, recovery
- How to recover missed Shopify orders after a webhook failure
- Shopify webhook retry policy: 8 retries, 4 hours, then dropped
- Webhook monitoring for Shopify apps: what to track and why
- Shopify webhook deduplication with X-Shopify-Event-Id
- Shopify auto-deleted my webhook subscription — what now?