Shopify Webhooks at Scale: Handling Idempotency, Retries, and 504 Timeouts
Allan M. Pedersen
Founder @ UseHookLens
When your Shopify store processes thousands of orders per hour, handling webhooks like `orders/create` or `inventory_levels/update` requires bulletproof architecture.
Shopify enforces two strict rules: 1. **At-Least-Once Delivery:** Events may be delivered multiple times. 2. **5-Second Timeout:** If your endpoint does not respond with `200 OK` within 5 seconds, Shopify marks the request as failed and retries with exponential backoff.
1. Guarding Against Duplicate Processing with Idempotency Keys
Because Shopify may dispatch the same event ID more than once due to network retries, your database must track processed event identifiers:
const eventId = req.headers.get('x-shopify-webhook-id');// Check if already processed const existing = await db.processedEvents.findUnique({ where: { id: eventId } });
if (existing) { // Acknowledge immediately to stop Shopify retries return NextResponse.json({ status: 'already_processed' }, { status: 200 }); }
// Mark as processing await db.processedEvents.create({ data: { id: eventId, processedAt: new Date() } }); ```
2. Eliminating 504 Gateway Timeouts
Never perform synchronous heavy operations (generating PDFs, sending marketing emails, calling 3rd-party ERPs) inside the webhook handler route.
Instead, follow the **Ingest & Queue** pattern: 1. Validate the `X-Shopify-Hmac-Sha256` signature. 2. Push the payload to an asynchronous worker queue (e.g. BullMQ, Redis, SQS). 3. Return `HTTP 200 OK` in under 50 milliseconds.
Monitor Everything with HookLens
With HookLens, you can monitor end-to-end Shopify webhook latency, spot retry spikes, and triage broken fulfillment events before your customers notice.
Diagnose Failed Webhooks in Real Time
Stop digging through raw server logs. Connect your Stripe & Shopify webhooks to HookLens and receive immediate AI root-cause analysis and code fixes.