Shopify Webhook HMAC Validation Failed? Fix Guide

Complete guide to webhooks, debugging, and real-time event monitoring with HookMetry

Shopify Webhook HMAC Validation Failed? Fix Guide

Problem Introduction

Shopify webhooks randomly fail X-Shopify-Hmac-SHA256 signature validation.

Why It Happens

  • Signing a parsed JSON object instead of raw bytes
  • Using hex encoding instead of base64 (Shopify requires base64)
  • Using the wrong App Secret — use the Shopify App Secret, not API key
  • Calling JSON.stringify(req.body) to reconstruct the body

Step-by-Step Fix

  1. 1Use express.raw() to capture the exact raw body bytes.
  2. 2Retrieve the X-Shopify-Hmac-SHA256 header.
  3. 3Hash the raw body using your App Secret with HMAC-SHA256.
  4. 4Encode the result as base64 (not hex — this is the key difference from Razorpay).
  5. 5Compare your base64 output with the header value.

Working Code

Copy-paste verified examples. Use the tab that matches your stack.

const crypto = require('crypto');

app.post('/webhooks/shopify', express.raw({ type: 'application/json' }), (req, res) => {
  const receivedHmac = req.headers['x-shopify-hmac-sha256'];
  if (!receivedHmac) return res.status(400).send('Missing HMAC header');

  // Shopify uses base64 — NOT hex (unlike GitHub/Razorpay)
  const computedHmac = crypto
    .createHmac('sha256', process.env.SHOPIFY_APP_SECRET)
    .update(req.body)    // raw Buffer from express.raw()
    .digest('base64');

  if (!crypto.timingSafeEqual(
    Buffer.from(receivedHmac),
    Buffer.from(computedHmac)
  )) {
    return res.status(401).send('HMAC validation failed');
  }

  const payload = JSON.parse(req.body);
  const topic   = req.headers['x-shopify-topic'];
  console.log('Shopify topic:', topic, 'shop:', req.headers['x-shopify-shop-domain']);
  res.status(200).json({ received: true });
});

Common Mistakes

  • Using `hex` encoding instead of `base64`
  • Using `JSON.stringify(req.body)` to recreate the payload

Debugging Workflow

Capture raw body → compute HMAC → base64 encode → compare → return 200.

Preventive Best Practices

  • Use Hookmetry to track encoding discrepancies between Shopify requests and your server.

Works with webhooks and other async event systems (including AI callbacks).

Instead of guessing, inspecting the exact payload and headers can help debug faster. Tools like Hookmetry support this workflow.

Try the free webhook tester

Was this page helpful?

Your feedback helps us improve the docs.