Shopify webhooks randomly fail X-Shopify-Hmac-SHA256 signature validation.
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');
sectionTitles: {problem: 'Why Is Your Shopify Webhook HMAC Validation Failing?', why: 'Root Causes of Shopify Webhook Signature Mismatches', fix: 'How to Fix Shopify X-Shopify-Hmac-SHA256 Validation', code: 'Working Shopify Webhook Signature Validation Code', mistakes: 'Most Common Shopify Webhook Signature Mistakes', workflow: 'Shopify Webhook Debugging Workflow', prevention: 'How to Prevent Shopify Signature Errors'},
},
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 });
});Capture raw body → compute HMAC → base64 encode → compare → return 200.
Works with webhooks and other async event systems (including AI callbacks). Instead of guessing, inspecting the exact payload and headers can help debug faster.
Try the free webhook testerWas this page helpful?
Your feedback helps us improve the docs.