Shopify Webhooks: Complete Developer Guide with Real Examples (2026)

shopify webhooks 8 min readMay 28, 2026

When you need your systems to react the moment something happens in a Shopify store — an order placed, a product updated, a customer registered — polling APIs every few seconds is not the answer. Shopify webhooks are. They push data to your endpoint the instant an event fires, making them the backbone of every serious real-time Shopify integration. Whether you are syncing orders to an ERP, triggering warehouse workflows, or feeding data into a CRM, understanding shopify webhooks end-to-end is non-negotiable for any developer working in the Shopify ecosystem.

This guide covers everything: what webhooks are, how to register them, how to verify their authenticity, and how to build reliable, production-grade consumers. Code examples are provided in Node.js and PHP throughout.

What Are Shopify Webhooks?

Per the official Shopify webhooks documentation, a Shopify webhook is an HTTP POST request that Shopify sends to a URL you define whenever a specific event occurs in a store. The request body contains a JSON payload describing the event — the order data, the product details, the customer record — depending on the topic subscribed to.

Webhooks are event-driven by design. Instead of your application asking Shopify "did anything change?" on a schedule, Shopify proactively notifies your endpoint. The flow looks like this:

  1. You register a webhook subscription for a specific topic (e.g., orders/create) and provide a destination URL.
  2. When that event occurs in the store, Shopify sends an HTTP POST to your URL within seconds.
  3. Your endpoint processes the payload and responds with an HTTP 2xx status code.
  4. If Shopify does not receive a 2xx within 5 seconds, it marks the delivery as failed and will retry.

This push-based model makes Shopify webhooks dramatically more efficient than any polling strategy and is the foundation of modern Shopify app development.

Shopify Webhooks vs Polling: Why Real-Time Wins

To appreciate why Shopify webhooks matter, consider the alternative. A polling approach queries the Shopify REST or GraphQL API on a fixed interval — say, every 30 seconds — asking for new or updated orders. This introduces several problems:

  • Latency: Events are only detected on the next poll cycle, introducing up to 30 seconds (or more) of delay.
  • API rate limits: Every poll consumes a request against Shopify's rate limit bucket (2 requests/second on REST, leaky-bucket on GraphQL). High-frequency polling burns through your allowance quickly.
  • Wasted compute: Most polls return nothing new, burning server resources and API quota for zero value.
  • Complexity: You need to track state — last-checked timestamps, cursor pagination — to avoid processing the same records twice.

Webhooks eliminate all of this. One registration, zero polling overhead, sub-second event delivery, and a clean separation between the trigger and the handler. For any integration that needs to feel real-time to the end user, webhooks are the only sensible choice.

Most Important Shopify Webhook Events

Shopify exposes dozens of shopify webhook events across its resources. The following table covers the topics you will encounter most often in production integrations:

TopicFires WhenTypical Use Case
orders/createA new order is placedERP sync, fulfilment trigger, email notification
orders/paidPayment is captured for an orderAccounting, revenue reporting, digital delivery
orders/updatedAny order field changesStatus sync, customer-facing order tracking
orders/cancelledAn order is cancelledInventory restock, refund processing
orders/fulfilledAll line items are fulfilledShipping confirmation emails, 3PL updates
products/createA new product is addedSync to marketplace, PIM, or search index
products/updateA product or its variants changePrice feed updates, catalog replication
customers/createA new customer account is createdCRM onboarding, welcome email sequence
customers/updateCustomer data changesCRM sync, consent management
inventory_levels/updateStock level changes at a locationLow-stock alerts, multi-channel inventory sync
checkouts/createA checkout session is openedAbandoned cart recovery workflows
checkouts/updateA checkout is modifiedAbandoned cart targeting, analytics
app/uninstalledYour app is uninstalled from a storeClean up access tokens and data
shop/updateStore settings changeLocale/currency sync

How to Create Shopify Webhooks

There are three ways to register Shopify webhooks: through the Admin UI (suitable for one-off setups), via the REST Admin API, or via the GraphQL Admin API (the modern, recommended approach for apps).

Via Shopify Admin UI

For quick manual setups or testing, navigate to Settings → Notifications → Webhooks in the Shopify Admin. Click Create webhook, select the event topic, set the format to JSON, and enter your endpoint URL. This method is fine for one store but does not scale to multi-merchant app deployments.

Via REST Admin API

Send a POST request to /admin/api/2024-01/webhooks.json with the topic and address:

POST /admin/api/2024-01/webhooks.json
Content-Type: application/json
X-Shopify-Access-Token: {access_token}

{
  "webhook": {
    "topic": "orders/create",
    "address": "https://yourapp.example.com/webhooks/orders-create",
    "format": "json"
  }
}

Shopify responds with the created webhook object including its id, which you can store and use for later deletion or updates.

Via GraphQL Admin API (Modern Approach)

For apps targeting the latest API versions, the GraphQL webhookSubscriptionCreate mutation is preferred. It supports HTTP and PubSub/EventBridge delivery simultaneously and gives fine-grained control over included fields:

mutation {
  webhookSubscriptionCreate(
    topic: ORDERS_CREATE
    webhookSubscription: {
      format: JSON
      callbackUrl: "https://yourapp.example.com/webhooks/orders-create"
    }
  ) {
    webhookSubscription {
      id
      topic
      callbackUrl
      createdAt
    }
    userErrors {
      field
      message
    }
  }
}

When building a full Shopify integration, programmatic registration via API is essential so that webhooks are automatically created during the OAuth install flow and torn down on uninstall. For a deeper look at the overall architecture, see our guide on building custom Shopify apps.

Shopify Webhook Payload Structure

Every Shopify webhook delivers a JSON body. Below is a condensed example of an orders/create payload showing the fields you will interact with most frequently in a shopify webhook implementation:

{
  "id": 5678901234567,
  "email": "customer@example.com",
  "created_at": "2024-03-15T14:22:01-05:00",
  "updated_at": "2024-03-15T14:22:01-05:00",
  "number": 1042,
  "note": null,
  "token": "b1946ac92492d2347c6235b4d2611184",
  "gateway": "shopify_payments",
  "total_price": "129.00",
  "subtotal_price": "119.00",
  "total_tax": "10.00",
  "currency": "USD",
  "financial_status": "paid",
  "fulfillment_status": null,
  "line_items": [
    {
      "id": 9876543210987,
      "variant_id": 44556677889900,
      "title": "Premium Widget",
      "quantity": 2,
      "sku": "PWD-001-BLK",
      "price": "59.50",
      "vendor": "Widget Co",
      "product_id": 112233445566778
    }
  ],
  "shipping_address": {
    "first_name": "Jane",
    "last_name": "Doe",
    "address1": "123 Main St",
    "city": "New York",
    "province": "New York",
    "country": "United States",
    "zip": "10001"
  },
  "customer": {
    "id": 33445566778899,
    "email": "customer@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "orders_count": 3
  }
}

Key fields to index on in your handler: id (use as idempotency key), financial_status, fulfillment_status, line_items[].sku for inventory matching, and customer.id for CRM lookup.

Verifying Shopify Webhook HMAC Signatures

Every Shopify webhook request includes an X-Shopify-Hmac-Sha256 header containing a Base64-encoded HMAC-SHA256 signature computed over the raw request body using your app's client secret. Shopify webhook verification is not optional — skipping it exposes your endpoint to spoofed payloads from any actor who discovers your URL.

The Shopify webhook HMAC verification process:

  1. Read the raw request body as bytes — do not parse JSON before this step.
  2. Compute HMAC-SHA256 of the raw body using your Shopify app client secret as the key.
  3. Base64-encode the result.
  4. Compare it to the value in the X-Shopify-Hmac-Sha256 header using a timing-safe comparison.
  5. Reject requests that do not match with a 401 response.

Node.js Verification Example

const crypto = require('crypto');

function verifyShopifyWebhook(req, secret) {
  const hmacHeader = req.headers['x-shopify-hmac-sha256'];
  if (!hmacHeader) return false;

  // req.rawBody must be the raw Buffer — set this in your body-parser config
  const digest = crypto
    .createHmac('sha256', secret)
    .update(req.rawBody)
    .digest('base64');

  // Timing-safe comparison prevents timing attacks
  const digestBuffer = Buffer.from(digest);
  const hmacBuffer = Buffer.from(hmacHeader);

  if (digestBuffer.length !== hmacBuffer.length) return false;

  return crypto.timingSafeEqual(digestBuffer, hmacBuffer);
}

// Express middleware usage
app.post('/webhooks/orders-create', express.raw({ type: 'application/json' }), (req, res) => {
  req.rawBody = req.body;

  if (!verifyShopifyWebhook(req, process.env.SHOPIFY_CLIENT_SECRET)) {
    return res.status(401).send('Unauthorized');
  }

  const order = JSON.parse(req.body);
  // Queue async processing — respond immediately
  orderQueue.add({ order });
  res.status(200).send('OK');
});

PHP Verification Example

Never use == or === for the comparison — always use a timing-safe function (crypto.timingSafeEqual in Node.js, hash_equals in PHP) to prevent timing-based attacks.

Shopify Webhook Best Practices

Respond with 2xx Within 5 Seconds

Shopify's delivery system expects your endpoint to return an HTTP 2xx status within 5 seconds. If it does not, the delivery is marked as failed. Do not do heavy lifting — database writes, external API calls, complex transformations — synchronously inside the handler. Acknowledge receipt immediately and hand off to a background worker.

Queue Async Processing

Use a message queue (Redis + BullMQ, RabbitMQ, SQS, or a simple database-backed job queue) to decouple reception from processing. Your webhook handler writes the raw payload to the queue and responds with 200. A separate worker picks it up and handles the business logic. This pattern also makes retries and dead-letter handling straightforward.

Handle Duplicates with Idempotency

Shopify may deliver the same webhook more than once — especially after retries. Use the payload's resource id field as an idempotency key. Before processing, check whether you have already handled that ID. If yes, return 200 immediately without reprocessing. A simple Redis SET with NX flag or a database unique constraint on the webhook ID works well.

Graceful Retry Handling

When Shopify cannot reach your endpoint, it retries delivery up to 19 times over 48 hours using an exponential backoff schedule. Your infrastructure must handle spikes — if your endpoint was down for an hour, you may receive a large burst of retried deliveries when it recovers. Design your queue and workers to handle burst load gracefully.

Log and Monitor

Log every incoming Shopify webhook — the topic, the resource ID, the timestamp, the processing outcome, and any errors. Set up alerting on error rates and processing lag. Shopify's Partner Dashboard (for public apps) and the Admin webhook settings page show recent delivery attempts and their HTTP response codes, which is invaluable for debugging production issues.

Common Shopify Webhook Events Use Cases

Order Sync to ERP

The orders/create and orders/paid shopify webhook events are the primary triggers for pushing order data into ERP systems such as SAP, NetSuite, or Dynamics 365. On receipt, your handler maps Shopify's order structure to the ERP's order schema, creates the sales order via the ERP's API, and stores the ERP reference back on the Shopify order using a metafield. For common pitfalls in this integration pattern, see our deep dive on Shopify ERP sync issues.

Inventory Sync

The inventory_levels/update topic fires whenever stock changes at any location. Subscribe to this topic to propagate inventory counts to other sales channels, marketplace listings, or a centralised inventory management system. Pay attention to the location_id field in the payload if the store operates multiple fulfilment locations.

Customer CRM Integration

Use customers/create and customers/update webhooks to keep your CRM — HubSpot, Salesforce, Klaviyo — in sync with Shopify customer data. Map the Shopify customer ID to the CRM contact ID and store both in each system so future events can be correlated without additional API lookups.

Abandoned Checkout Notifications

The checkouts/create and checkouts/update topics let you build abandoned cart recovery flows outside of Shopify's native tooling. When a checkout is created, start a timer. If no orders/create event arrives within your threshold window (typically 1–3 hours), send a recovery email or SMS via your preferred messaging platform. Store the token field from the checkout payload to reconstruct the recovery URL.

Debugging Shopify Webhooks

Testing Shopify webhooks during local development requires exposing your local server to the internet. Several tools make this straightforward:

  • ngrok: Run ngrok http 3000 to get a public HTTPS URL tunnelled to your local port. Register this URL as your webhook endpoint in Shopify, then inspect every request and response in ngrok's local dashboard at http://localhost:4040. The replay feature lets you re-send captured payloads without triggering a real store event.
  • Shopify CLI: The Shopify CLI (shopify app dev) automatically handles tunnelling and webhook registration for app development, forwarding delivery attempts directly to your local server.
  • webhook.site: Generate a free public URL at webhook.site to inspect raw payloads without writing any code. Useful for quickly examining the exact JSON structure Shopify sends for a given topic before you write your handler.
  • Shopify Admin delivery logs: Under Settings → Notifications → Webhooks, each registered webhook shows its most recent delivery attempts with the HTTP status returned. This is your first debugging stop in production.

When verifying signatures locally, make sure your client secret matches the app registered in the Partner Dashboard — a common source of 401 errors during development is using a test secret that does not match the store's installed app.

Webhook Limits and Scaling Considerations

Before going to production with a Shopify webhook implementation, understand the platform's limits and failure behaviours:

  • 5-second response window: Hard limit. Any response taking longer is treated as a failure regardless of the eventual outcome. Asynchronous queue offloading is mandatory for any non-trivial processing.
  • Retry schedule: Shopify retries failed deliveries up to 19 times. Retries follow an exponential backoff over approximately 48 hours. After 19 consecutive failures, the webhook subscription is automatically deleted by Shopify — you will lose the subscription silently. Monitor for this and implement automatic re-registration logic in your app.
  • Delivery ordering: Shopify does not guarantee in-order delivery. A burst of rapid updates to the same resource may arrive out of sequence. Use the updated_at timestamp in the payload to detect stale events and discard them if a newer event has already been processed.
  • Webhook volume at scale: High-volume merchants can generate thousands of webhook events per minute during flash sales. Size your ingestion layer (reverse proxy, queue) to handle peak burst, not average throughput. Consider a dedicated webhook ingestion service separate from your main application.
  • Subscription limits: Shopify allows up to 1,000 webhook subscriptions per app per store. In practice you will rarely approach this, but be aware of the limit in multi-topic integrations.
  • HTTPS required: All webhook endpoints must use HTTPS with a valid TLS certificate. Self-signed certificates are not accepted in production (only in development via tools like ngrok).

Conclusion

Mastering Shopify webhooks is a fundamental skill for any developer building production-grade integrations with the Shopify platform. From registering subscriptions via the GraphQL API to verifying Shopify webhook HMAC signatures in constant time, every step in the pipeline has sharp edges that separate a fragile prototype from a robust, scalable system. The patterns covered here — async queue offloading, idempotency keys, graceful retry handling, comprehensive logging — apply regardless of whether you are processing ten orders a day or ten thousand.

If you need an expert team to design and build your Shopify integration from the ground up, the specialists at MGroup have deep experience in Shopify app development across ERP connectors, marketplace integrations, and custom automation workflows. Reach out to discuss your project requirements.

FAQ

What are Shopify webhooks used for?

Shopify webhooks send an HTTP POST to your endpoint when a store event happens, such as an order or product update. They let systems react in real time instead of polling the API.

Which shopify webhook events are most common in integrations?

Common shopify webhook events include orders/create, orders/paid, products/update, customers/create, inventory_levels/update, and app/uninstalled. Each supports a different sync or workflow.

How do you create Shopify webhooks for an app?

You can create Shopify webhooks in Admin, via the REST Admin API, or with the GraphQL Admin API. For apps, the article recommends API-based shopify webhook implementation during install.

How does Shopify webhook verification work?

Shopify webhook verification uses the X-Shopify-Hmac-Sha256 header. You compute an HMAC-SHA256 on the raw body with your client secret, Base64-encode it, and compare it safely before processing.

Why should webhook handlers respond quickly?

Shopify expects a 2xx response within 5 seconds. If the endpoint is slower, the delivery is marked failed and retried, so handlers should queue work and return fast.

This website uses cookies

We use cookies to personalise content and ads, to provide social media features and to analyse our traffic.

Close