Prompt
Shopify webhook signature verification
Latest observation
Oct 5, 2026
OpenAI APIWeb search: off
To verify a Shopify webhook signature, you should compute an HMAC of the raw request body using your app’s Shopify API secret, then compare it to the value in the X-Shopify-Hmac-Sha256 header.
Verification steps
- Read the raw body exactly as received
- Do not parse and re-serialize JSON before verifying.
- Compute:
HMAC_SHA256(raw_body, your_shopify_api_secret)
- Base64-encode the result.
- Compare it to the header:
X-Shopify-Hmac-Sha256
- Use a constant-time comparison.
Example in Node.js
import crypto from "crypto";
function verifyShopifyWebhook(req, secret) {
const hmacHeader = req.headers["x-shopify-hmac-sha256"];
const rawBody = req.rawBody; // must be the exact raw request body string/buffer
const digest = crypto
.createHmac("sha256", secret)
.update(rawBody, "utf8")
.digest("base64");
return crypto.timingSafeEqual(
Buffer.from(digest, "utf8"),
Buffer.from(hmacHeader, "utf8")
);
}
Important notes
- In Express, you usually need middleware that captures the raw body before JSON parsing.
- If you use
express.json(), it may destroy the raw payload needed for verification unless configured properly.
Example raw body capture in Express
import express from "express";
import crypto from "crypto";
const app = express();
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf.toString("utf8");
}
}));
app.post("/webhooks", (req, res) => {
const hmacHeader = req.header("X-Shopify-Hmac-Sha256");
const secret = process.env.SHOPIFY_API_SECRET;
const digest = crypto
.createHmac("sha256", secret)
.update(req.rawBody, "utf8")
.digest("base64");
const valid =
hmacHeader &&
crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(hmacHeader));
if (!valid) return res.status(401).send("Invalid signature");
res.sendStatus(200);
});
Common mistakes
- Verifying against
JSON.stringify(req.body) - Using the wrong secret
- Comparing the signature with normal string equality
- Forgetting to use the raw request body
- Using the wrong header name
Header to check
X-Shopify-Hmac-Sha256
If you want, I can also give you:
- a Python, Ruby, PHP, Go, or Laravel example
- a version for Next.js / API routes
- help debugging a failing webhook verification