Skip to content
cascadehook.

ToolsFree tool

Shopify webhook HMAC verifier

Check an X-Shopify-Hmac-Sha256 header against your app's client secret and see why the HMAC doesn't match. Nothing you paste leaves your browser.

Paste request headers

Paste the headers from a log, a request inspector, or curl -v, as Name: value lines or JSON. The matching fields below are filled in.

Signature your code computed (optional)

If your code rejects a request that verifies here, print the signature it computes for this request and paste it. The tool finds which mistake produces that value.

Runs entirely in your browser with Web Crypto. Nothing you paste is sent anywhere or saved.

The result shows up here

Paste your app's client secret, the X-Shopify-Hmac-Sha256 header, and the raw body from a delivery, then verify. To see how it works first, use Try an example.

What gets signed

Base64(HMAC-SHA256(client secret, body))

The body was parsed before it was verified

Shopify signs the raw body. If express.json() or another parser runs first, the body you hash is a re-serialized copy. Use express.raw({ type: "application/json" }) on the webhook route, or read the raw body before your framework parses it. Apps built from Shopify's templates can call authenticate.webhook(request), which verifies the HMAC for you.

The wrong secret

Webhooks an app subscribes to are signed with that app's client secret, shown next to its client ID in the app's settings. It isn't the API key, an Admin API access token (shpat_…), or the secret of another app.

The webhook was created in the store admin

Webhooks created under Settings → Notifications in the Shopify admin aren't tied to an app. Developers report that they're signed with the key shown on that page rather than an app's client secret.

The secret was just rotated

After you rotate the client secret, Shopify can take up to an hour to start signing with the new one. Accept both secrets until the change has taken effect.

The HMAC is compared as hex

The header is Base64, not hex. Encode your digest as Base64 before comparing, or decode the header to bytes and compare those with crypto.timingSafeEqual.

Sending webhooks from your own product? Cascadehook signs every delivery with Standard Webhooks, retries failures for up to 72 hours, and keeps every attempt for replay. Create a project or try the Standard Webhooks verifier.

Shopify is a trademark of Shopify Inc.. Cascadehook isn't affiliated with or endorsed by Shopify.