How to Test Shopify Webhooks Locally
What Webhooks Does Shopify Send?
Shopify uses webhooks to notify your app about events in a merchant's store. Key events include orders/create, orders/paid, orders/fulfilled, products/create, products/update, customers/create, carts/update, refunds/create, and app/uninstalled. These are essential for building Shopify apps that react to store activity in real time.
Shopify sends webhook payloads as JSON with an X-Shopify-Topic header indicating the event type, an X-Shopify-Hmac-Sha256 header for signature verification, and X-Shopify-Shop-Domain identifying which store triggered the event. The body contains the full resource — for example, an orders/create payload includes the complete order object with line items, customer info, shipping address, and payment details.
During development, you need a public URL for Shopify to reach. The Shopify CLI has a built-in tunnel, but it changes every session. ReqPour gives you a stable URL that persists across restarts, plus a visual inspector for examining payloads.
Configuring Shopify Webhooks with ReqPour
There are two ways to register Shopify webhooks: through the admin UI or via the API. For the admin UI approach, go to Settings > Notifications in your Shopify admin, scroll to Webhooks, and click "Create webhook." Select the event, set the format to JSON, and paste your ReqPour endpoint URL.
For API-based registration (common in Shopify apps), use the Admin API:
const response = await fetch(
`https://${shop}/admin/api/2024-01/webhooks.json`,
{
method: 'POST',
headers: {
'X-Shopify-Access-Token': accessToken,
'Content-Type': 'application/json',
},
body: JSON.stringify({
webhook: {
topic: 'orders/create',
address: 'https://abc123.reqpour.com/shopify',
format: 'json',
},
}),
}
);Register your ReqPour URL as the address. Once configured, any matching store event will appear in the ReqPour dashboard immediately.
Inspecting Shopify Payloads
Shopify webhook payloads can be large, especially for orders with many line items. The ReqPour request inspector renders the full JSON with syntax highlighting and collapsible sections, making it easier to navigate complex payloads than reading raw logs.
Pay attention to the X-Shopify-Topic header — it tells you exactly which event fired. Filter by this header in the dashboard to focus on specific event types. The X-Shopify-Shop-Domain header is useful when your app serves multiple stores.
One thing to watch for: Shopify sends webhooks for events triggered by your app too. If your app creates an order via the API, you will receive an orders/create webhook. This can cause infinite loops if your webhook handler also calls the API. Use the X-Shopify-Webhook-Id header to deduplicate and prevent this.
Relaying and Handling Shopify Webhooks
Start the ReqPour relay to forward Shopify events to your local development server:
npx reqpour relay --to http://localhost:3000/api/webhooks/shopifyHere is a handler that verifies the Shopify HMAC signature:
const crypto = require('crypto');function verifyShopifyWebhook(req) { const hmac = req.headers['x-shopify-hmac-sha256']; const body = req.rawBody; // need raw body for verification const hash = crypto .createHmac('sha256', process.env.SHOPIFY_WEBHOOK_SECRET) .update(body) .digest('base64'); return crypto.timingSafeEqual( Buffer.from(hmac), Buffer.from(hash) ); }
app.post('/api/webhooks/shopify', (req, res) => { if (!verifyShopifyWebhook(req)) { return res.status(401).send('Invalid signature'); } const topic = req.headers['x-shopify-topic']; switch (topic) { case 'orders/create': handleNewOrder(req.body); break; case 'products/update': handleProductUpdate(req.body); break; } res.status(200).send('OK'); }); ```
Note the base64 encoding for Shopify's HMAC — this differs from GitHub's hex encoding. The ReqPour dashboard lets you compare the computed hash with the header value to debug verification issues.
Shopify Webhook Development Tips
Shopify has a 5-second timeout for webhook responses. After 19 consecutive failures, Shopify removes the webhook subscription entirely. During development, use ReqPour to monitor response times and catch slow handlers before they cause failures.
Mandatory webhooks are required for all Shopify apps and include app/uninstalled, customers/data_request, customers/redact, and shop/redact. These are configured in your Partner Dashboard, not via the API. Point them at your ReqPour URL during development to test GDPR compliance handlers.
Use ReqPour's replay feature to test your handler with different order configurations — orders with discounts, orders with multiple shipping addresses, orders with digital products — without having to create test orders in your development store each time.
Related
Get started with ReqPour
Catch, inspect, and relay webhooks to localhost. Free to start, $3/mo for Pro.