Shopify Webhook Guide

How to receive, verify, test, and monitor Shopify webhooks — with HMAC-SHA256 verification code and common pitfalls.

Last updated March 2026. Covers Shopify API version 2025-10 and later.

1

What Are Shopify Webhooks?

Shopify webhooks notify your application in real time when events happen in a store — an order is placed, a product is updated, a customer signs up, or an app is uninstalled. Instead of polling the Shopify API, your server receives an HTTP POST with a JSON payload the moment the event occurs.

Common Shopify webhook event types:

orders/create orders/paid orders/fulfilled products/update products/create checkouts/create app/uninstalled customers/create refunds/create carts/update
2

Setting Up via Shopify Admin

The simplest way to register webhooks is through the Shopify Admin dashboard:

  1. Log in to your Shopify Admin panel.
  2. Go to Settings → Notifications.
  3. Scroll down to the Webhooks section and click "Create webhook".
  4. Select the Event topic (e.g. Order creation).
  5. Choose JSON as the format.
  6. Paste your endpoint URL and click "Save".

Shopify will send a test POST to verify your endpoint is reachable. Make sure it returns a 200 status code.

You can also register webhooks programmatically via the Shopify Admin API using the POST /admin/api/2025-10/webhooks.json endpoint.

3

Verifying HMAC-SHA256 Signatures

Shopify signs every webhook with HMAC-SHA256 using your app's shared secret. The signature is sent in the X-Shopify-Hmac-Sha256 header as a base64-encoded string. Always verify this before processing the payload.

const crypto = require('crypto');
const express = require('express');
const app = express();

const SHOPIFY_SECRET = process.env.SHOPIFY_WEBHOOK_SECRET;

app.post('/webhook/shopify',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const hmacHeader = req.headers['x-shopify-hmac-sha256'];

    // Compute HMAC from the raw body
    const computed = crypto
      .createHmac('sha256', SHOPIFY_SECRET)
      .update(req.body)
      .digest('base64');

    // Constant-time comparison to prevent timing attacks
    if (!crypto.timingSafeEqual(
      Buffer.from(hmacHeader, 'utf8'),
      Buffer.from(computed, 'utf8')
    )) {
      console.error('HMAC verification failed');
      return res.status(401).send('Unauthorized');
    }

    // Signature verified — safe to process
    const payload = JSON.parse(req.body);
    const topic = req.headers['x-shopify-topic'];
    console.log('Verified Shopify webhook:', topic);

    switch (topic) {
      case 'orders/create':
        console.log('New order:', payload.id, payload.total_price);
        break;
      case 'app/uninstalled':
        console.log('App uninstalled from shop:', payload.domain);
        break;
      default:
        console.log('Unhandled topic:', topic);
    }

    res.status(200).json({ received: true });
  }
);

app.listen(3000, () => console.log('Shopify webhook server on port 3000'));

Critical: use the raw request body for HMAC computation, not parsed JSON. If you use express.json() middleware globally, it will alter the body and break verification. Apply express.raw({ type: 'application/json' }) specifically on the webhook route.

4

Testing with SDNBros

During development, Shopify needs a publicly reachable URL to send webhooks. Here's the fastest way to test:

  1. Open the SDNBros Webhook Tester — get a public endpoint URL instantly, no signup required.
  2. In Shopify Admin, go to Settings → Notifications → Webhooks. Click "Create webhook" and paste your SDNBros URL.
  3. Select an event topic (e.g. Order creation) and format JSON.
  4. Trigger a test event by creating a test order in your development store, or use the "Send test notification" button next to the webhook.
  5. Switch back to SDNBros — you'll see the event arrive in real time with full headers, body, and HMAC signature. SDNBros auto-detects it as a Shopify webhook and shows the topic.

You can also use the quick-send buttons in the tester to fire a simulated Shopify orders/create event without leaving the page.

5

Monitoring in Production

In production, missed Shopify webhooks mean missed orders, stale inventory, or broken integrations. Set up proper monitoring:

Common Shopify Webhook Issues

IssueCauseFix
HMAC verification failedUsing parsed JSON body instead of raw body, or wrong shared secretUse express.raw() on the webhook route. Verify your shared secret matches the one in Shopify Admin > Notifications > Webhooks.
Webhook removed after failuresShopify automatically deletes webhooks after 19 consecutive failed deliveriesMonitor your endpoint uptime. Re-register the webhook via Admin or API after fixing the issue.
Duplicate events receivedShopify retries webhooks that don't receive a 200 response within 5 secondsReturn 200 immediately and process asynchronously. Store event IDs and check for duplicates.
Webhooks not arrivingEndpoint not publicly accessible, SSL/TLS issues, or firewall blocking Shopify IPsVerify the URL is correct and reachable. Ensure a valid SSL certificate. Check firewall rules.
Timeout / slow responseEndpoint takes too long to respond. Shopify expects a response within 5 seconds.Return 200 immediately. Move heavy processing (DB writes, API calls) to a background queue.

Test Shopify webhooks free

Create a public endpoint and inspect Shopify payloads and HMAC behavior. No signup is needed for the tester.

Open Webhook Tester Monitor in Production

Related guides: What is a Webhook? · Webhook vs API · Webhook Security · Retry Strategies · Stripe · GitHub · Slack

More: What is a Webhook? | Webhook Security Guide | Stripe Webhook Guide | GitHub Webhook Guide | Compare Tools