SHOPIFY WEBHOOKS
Shopify webhook HMAC verification failing — valid events rejected
Shopify signs every delivery with X-Shopify-Hmac-Sha256. If your verification fails — wrong secret, mutated body, encoding issues — every real event gets rejected while Shopify counts the delivery as "responded to."
Why Shopify webhooks fail silently
Body parsing before verification
HMAC covers the raw bytes. If your framework JSON-parses or re-serializes the body first, the signature never matches.
Wrong secret for the webhook source
App-created webhooks verify with the app’s API secret; admin-created webhooks use a different credential. Mixing them fails every time.
Base64 comparison bugs
Comparing raw HMAC output to the base64 header without encoding — or using strict equality instead of timing-safe compare — produces false rejections.
The fix
- 1
Verify the raw request body
Hash the unparsed body with your secret, base64-encode, and compare to X-Shopify-Hmac-Sha256 using a timing-safe comparison.
- 2
Use the right credential
App webhooks → your app’s API secret key. Admin-panel webhooks → the credential shown when the webhook was created.
- 3
Log rejections separately from errors
A 401 from failed verification should page differently than a 500 — it means traffic is flowing but being thrown away.
- 4
Record every attempt
HookShield logs each delivery attempt and your target’s response — a wall of 401s on the dashboard beats finding out from a merchant.
DEAD-MAN'S SWITCH
Never find out about a dead webhook from a customer again
Point Shopify at a HookShield ingest URL. Every delivery is logged, signed, and forwarded — and if pings stop arriving, you're alerted before the silence becomes an incident.