Skip to main content

Subscribing to webhooks

Your app must respond to mandatory webhook topics. In addition, your app can register optional webhook topics.

There are app-specific and shop-specific webhooks. We recommend app-specific webhooks for most apps, but there are reasons to register shop-specific webhooks. For more information, please read App-specific vs shop-specific webhooks.


Anchor to configApp-specific webhooks (recommended)

The easiest way to configure webhooks is to use app-specific webhooks in shopify.app.toml. You can find more info in the webhooks documentation.

To set up a simple HTTPS webhook subscription, you can follow these steps:

  1. Add the topic to subscribe to in shopify.app.toml. In this example we subscribe to the APP_UNINSTALLED topic.
  2. Review the required scopes for the webhook topics, and update your app scopes as necessary.
  3. Run shopify app deploy from the CLI to save your webhooks configuration.

Configure app-specific webhooks

shopify.app.toml

[webhooks]
api_version = "2024-04"

[[webhooks.subscriptions]]
topics = [ "app/uninstalled" ]
uri = "/webhooks"
compliance_topics = [ "customers/data_request", "customers/redact", "shop/redact" ]

Anchor to configShop-specific webhooks

Shop-specific webhooks are useful when you need to subscribe to different webhook topics for different shops, or when a topic is not supported by app-specific webhooks.Configure shopifyApp and to setup shop-specific webhook subscriptions with the following steps:

  1. The webhooks you want to subscribe to. In this example we subscribe to the APP_UNINSTALLED topic.
  2. The code to register the APP_UNINSTALLED topic after a merchant installs you app. Here shopifyApp provides an afterAuth hook.
  3. Review the required scopes for the webhook topics, and update your app scopes as necessary.
Note

You can't register mandatory topics using this package, you must configure those in the Partner Dashboard instead.

Configure shop-specific webhooks

/app/shopify.server.ts

import {shopifyApp, DeliveryMethod} from '@shopify/shopify-app-react-router/server';

const shopify = shopifyApp({
apiKey: 'abcde1234567890',
// ...etc
webhooks: {
APP_UNINSTALLED: {
deliveryMethod: DeliveryMethod.Http,
callbackUrl: '/webhooks',
},
},
hooks: {
afterAuth: async ({session}) => {
// Register webhooks for the shop
// In this example, every shop will have these webhooks
// You could wrap this in some custom shop specific conditional logic if needed
shopify.registerWebhooks({session});
},
},
});

export const authenticate = shopify.authenticate;

Anchor to endpointsSet up your endpoints

Create a route in your app to handle incoming webhook requests for each callbackUrl you set in your configuration.Legitimate webhook requests are always POST requests signed by Shopify, so you must authenticate them before taking any action. To do this you must set up an action that uses the authenticate.webhook function to authenticate the request.

Please keep in mind that webhook endpoints should respond as quickly as possible. If you need to run a long-running job, then consider using background tasks.

Caution

Webhook endpoints must respond with an HTTP 200 code, or Shopify will retry.

Receive webhook requests

/app/routes/webhooks.tsx

import {ActionFunctionArgs} from 'react-router';

import db from '../db.server';

import {authenticate} from '~/shopify.server';

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

switch (topic) {
case 'APP_UNINSTALLED':
// Webhook requests can trigger after an app is uninstalled
// If the app is already uninstalled, the session may be undefined.
if (session) {
await db.session.deleteMany({where: {shop}});
}
break;
case 'CUSTOMERS_DATA_REQUEST':
case 'CUSTOMERS_REDACT':
case 'SHOP_REDACT':
default:
throw new Response('Unhandled webhook topic', {status: 404});
}

throw new Response();
};