ShopIntegrations
Integrations

The Definitive Guide to Handling Shopify Webhooks in Next.js

8 min read
Shop Integrations Engineering

Webhooks are the lifeblood of any Shopify app or custom integration. They notify your application when products update, orders are created, or customers update their profiles. But handling them correctly in a modern Next.js environment (especially the App Router) requires passing security checks, handling timeouts, and structuring your code for scale.

The Anatomy of a Shopify Webhook

When an event occurs in a Shopify store, Shopify sends an HTTP POST request to your configured endpoint. This request contains two critical pieces of information:

  • Headers: Such as X-Shopify-Topic and the vital X-Shopify-Hmac-Sha256.
  • Body: The JSON payload containing the event data.

If your endpoint doesn't respond with a 200 OK within 5 seconds, Shopify considers it a failure and will retry it later.

Step 1: HMAC Verification in Next.js App Router

You must verify that the webhook actually came from Shopify. You do this by calculating the HMAC hash of the raw request body using your app's shared secret and comparing it to the X-Shopify-Hmac-Sha256 header.

In the App Router (app/api/webhooks/route.ts), you must read the body as text to get the exact raw string before parsing it to JSON.

import crypto from 'crypto';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  const rawBody = await req.text();
  const signature = req.headers.get('x-shopify-hmac-sha256');
  const secret = process.env.SHOPIFY_WEBHOOK_SECRET!;

  const hash = crypto
    .createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('base64');

  if (hash !== signature) {
    return new NextResponse('Unauthorized', { status: 401 });
  }

  // Verification passed!
  const payload = JSON.parse(rawBody);
  // ... process payload ...
}

Step 2: Beating the 5-Second Timeout

Because Shopify requires a rapid response, you should not do heavy processing (like complex database queries, ERP syncing, or sending emails) directly inside the API route handler.

For Vercel or standard Node.js deployments, the best practice is to immediately push the payload to a queue (like Inngest, Upstash QStash, or AWS SQS) and return a 200 OK.

Step 3: Idempotency is Mandatory

Shopify webhooks follow "at-least-once" delivery. This means Shopify might send the same webhook twice. Your background worker must be idempotent. Always check if you have already processed the specific X-Shopify-Webhook-Id before running your business logic.

Step 4: Managing Rate Limits

If a merchant updates 1,000 products via CSV, Shopify fires 1,000 webhooks at your endpoint almost simultaneously. If you're doing database writes directly from your webhook handler without an intermediary queue, you will quickly exhaust your connection pool and fail handling webhooks.

Conclusion

Building a durable webhook handler in Next.js requires separating your verification logic from your business logic. By prioritizing rapid responses and pushing the heavy lifting to asynchronous background jobs, you ensure your integration remains highly reliable even under massive load.

Need help with this?

We have built these patterns into production systems for dozens of merchants. See how we can help you implement them.

Get the 7-day readiness audit

Identify reliability gaps, integration risks, and automation opportunities. Get a concrete action plan in one week.