home / skills / toilahuongg / shopify-agents-kit / shopify-webhooks

shopify-webhooks skill

/.claude/skills/shopify-webhooks

This skill guides you through configuring, verifying, and handling Shopify webhooks to keep data in sync securely.

npx playbooks add skill toilahuongg/shopify-agents-kit --skill shopify-webhooks

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.3 KB
---
name: shopify-webhooks
description: Guide for handling Shopify Webhooks, including configuration, verification, and processing. Use this skill when the user needs to set up webhook subscriptions, verify authentic requests, or handle event payloads.
---

# Shopify Webhooks Skill

Webhooks are the preferred way to stay in sync with Shopify data. They allow your app to receive real-time notifications when events occur in a shop (e.g., `orders/create`, `app/uninstalled`).

## 1. Verification (CRITICAL)

**ALL** webhook requests must be verified to ensure they came from Shopify.

### HMAC Verification

Shopify includes an `X-Shopify-Hmac-Sha256` header in every webhook request. This is a base64-encoded HMAC-SHA256 digest of the request body, using your **Client Secret** (API Secret Key) as the signing key.

> [!IMPORTANT]
> Always use the **raw request body** (Buffer) for verification. Parsed JSON bodies may have subtle differences that cause verification to fail.

#### Node.js Example (Generic)

```javascript
const crypto = require('crypto');

function verifyWebhook(rawBody, hmacHeader, apiSecret) {
  const digest = crypto
    .createHmac('sha256', apiSecret)
    .update(rawBody, 'utf8')
    .digest('base64');

  return crypto.timingSafeEqual(
    Buffer.from(digest),
    Buffer.from(hmacHeader)
  );
}
```

#### Remix / Shopify App Template (Recommended)

If using `@shopify/shopify-app-remix`, verification is handled automatically by the `authenticate.webhook` helper.

```typescript
/* app/routes/webhooks.tsx */
import { authenticate } from "../shopify.server";

export const action = async ({ request }) => {
  const { topic, shop, session, admin, payload } = await authenticate.webhook(request);

  if (!admin) {
    // The webhook request was not valid.
    return new Response();
  }

  switch (topic) {
    case "APP_UNINSTALLED":
      if (session) {
        await db.session.deleteMany({ where: { shop } });
      }
      break;
    case "ORDERS_CREATE":
      console.log(`Order created: ${payload.id}`);
      break;
  }

  return new Response();
};
```

## 2. Registration

### App-specific Webhooks (Recommended)
These are configured in `shopify.app.toml`. They are automatically registered when the app is deployed and are easier to manage. Best for topics that apply to the app in general (e.g., `app/uninstalled`).

```toml
[webhooks]
api_version = "2025-10"

  [[webhooks.subscriptions]]
  topics = [ "app/uninstalled", "orders/create" ]
  uri = "/webhooks"
```

### Shop-specific Webhooks (Advanced)
Use `webhookSubscriptionCreate` via the Admin API. Best for:
- Per-shop customization.
- Topics not supported by config.
- Dynamic runtime registration.

```graphql
mutation webhookSubscriptionCreate($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
  webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
    userErrors {
      field
      message
    }
    webhookSubscription {
      id
    }
  }
}
```

## 3. Mandatory Compliance (GDPR)

Public apps **MUST** implement specific webhooks to comply with privacy laws. These are configured in the **Partner Dashboard** (App > Configuration > Privacy compliance), NOT in `shopify.app.toml` or via API.

-   `customers/data_request`: Request to export customer data.
-   `customers/redact`: Request to delete customer data.
-   `shop/redact`: Request to delete shop data (48 hours after uninstall).

> [!WARNING]
> Failure to handle these can result in app removal.

## 4. Best Practices

-   **Idempotency**: Webhooks can be delivered multiple times. Ensure your processing logic is idempotent (e.g., check if an order has already been processed before taking action).
-   **Response Time**: Respond with a `200 OK` **immediately** (within 5 seconds). Perform long-running tasks asynchronously (e.g., using a background queue).
-   **App Uninstalled**: ALWAYS handle `app/uninstalled` to clean up shop data and cancel subscriptions. This webhook acts as the "offboarding" signal.
-   **App Uninstalled**: ALWAYS handle `app/uninstalled` to clean up shop data and cancel subscriptions. This webhook acts as the "offboarding" signal.

## Common Topics

-   `APP_UNINSTALLED`: App removed. Cleanup required.
-   `ORDERS_CREATE`: New order placed.
-   `ORDERS_PAID`: Order payment status changed to paid.
-   `PRODUCTS_UPDATE`: Product details changed.

Overview

This skill guides you through configuring, verifying, and processing Shopify webhooks so your app stays in sync with store events. It covers secure HMAC verification, registration options (app-configured and shop-specific), mandatory GDPR webhooks, and practical processing guidelines. Use it to implement reliable, compliant webhook handling for real-time Shopify notifications.

How this skill works

The skill explains how to verify incoming webhook requests using the X-Shopify-Hmac-Sha256 header and your API secret, emphasizing use of the raw request body for HMAC computation. It shows automatic verification options for common frameworks and how to register subscriptions either via a deployment config (recommended) or the Admin API for per-shop cases. It also describes required GDPR webhooks and how to respond quickly while delegating long work to background jobs.

When to use it

  • Setting up initial webhook subscriptions for your Shopify app
  • Verifying webhook request authenticity to prevent spoofing
  • Implementing app uninstall and GDPR-compliance handlers
  • Registering per-shop or dynamic runtime subscriptions
  • Designing idempotent processing and async handling for events

Best practices

  • Always verify requests using HMAC-SHA256 against the raw request body and your API secret
  • Respond with 200 OK within 5 seconds; perform heavy work asynchronously (queues, workers)
  • Make processing idempotent to handle duplicate deliveries safely
  • Handle app/uninstalled to remove shop data and cancel subscriptions
  • Register app-level webhooks via configuration for consistent deployment; use Admin API for dynamic, per-shop needs

Example use cases

  • Automatically clean up shop records and tokens when APP_UNINSTALLED arrives
  • Queue order processing and fulfillment when ORDERS_CREATE is received
  • Update product caches or search indexes on PRODUCTS_UPDATE events
  • Expose customers/data_request and customers/redact endpoints to meet GDPR obligations
  • Create per-shop webhooks via the Admin API for custom store-level integrations

FAQ

What header and algorithm are used to verify Shopify webhooks?

Shopify sends X-Shopify-Hmac-Sha256 which is a base64 HMAC-SHA256 digest of the raw request body signed with your API secret.

Should I parse the request body before verification?

No. Always use the raw request body (bytes/Buffer) for HMAC verification; parsing can alter formatting and break the signature check.