Skip to main content

Webhook
object

Contains functions for verifying Shopify webhooks.

Note

The format of the admin object returned by this function changes with the v3_webhookAdminContext future flag. Learn more about gradual feature adoption.

Verifies requests coming from Shopify webhooks.

Request
required

Promise<<Future, Resources, Topics>>
Was this section helpful?

Update a metafield when a product is updated

/app/routes/**.ts

import {type ActionFunctionArgs} from '@remix-run/node';

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

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

switch (topic) {
case 'PRODUCTS_UPDATE':
await admin.graphql(
`#graphql
mutation setMetafield($productId: ID!, $time: String!) {
metafieldsSet(metafields: {
ownerId: $productId
namespace: "my-app",
key: "webhook_received_at",
value: $time,
type: "string",
}) {
metafields {
key
value
}
}
}
`,
{
variables: {
productId: payload.admin_graphql_api_id,
time: new Date().toISOString(),
},
},
);

return new Response();
}

throw new Response();
};

With the v3_webhookAdminContext future flag enabled, use the admin object in the context to interact with the Admin API.

Use the admin object in the context to interact with the Admin API. This format will be removed in V3 of the package.

Was this section helpful?

[V3] Webhook admin context

/app/routes/webhooks.tsx

import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";

export async function action({ request }: ActionFunctionArgs) {
const { admin } = await authenticate.webhook(request);

const response = await admin?.graphql(
`#graphql
mutation populateProduct($input: ProductInput!) {
productCreate(input: $input) {
product {
id
}
}
}`,
{ variables: { input: { title: "Product Name" } } }
);

const productData = await response.json();
return json({ data: productData.data });
}

Get the API version used for webhook request.

Was this section helpful?

Webhook API version

/app/routes/webhooks.tsx

import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";

export const action = async ({ request }: ActionFunctionArgs) => {
const { apiVersion } = await authenticate.webhook(request);
return new Response();
};

Get the shop that triggered a webhook.

Was this section helpful?

Webhook shop

/app/routes/webhooks.tsx

import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";

export const action = async ({ request }: ActionFunctionArgs) => {
const { shop } = await authenticate.webhook(request);
return new Response();
};

Get the event topic for the webhook.

Was this section helpful?

Webhook topic

/app/routes/webhooks.tsx

import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";

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

switch (topic) {
case "APP_UNINSTALLED":
// Do something when the app is uninstalled.
break;
}

return new Response();
};

Get the webhook ID.

Was this section helpful?

Webhook ID

/app/routes/webhooks.tsx

import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";

export const action = async ({ request }: ActionFunctionArgs) => {
const { webhookId } = await authenticate.webhook(request);
return new Response();
};

Get the request's POST payload.

Was this section helpful?

Webhook payload

/app/routes/webhooks.tsx

import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";

export const action = async ({ request }: ActionFunctionArgs) => {
const { payload } = await authenticate.webhook(request);
return new Response();
};

Get the webhook sub-topic.

Was this section helpful?

Webhook sub-topic

/app/routes/webhooks.tsx

import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";

export const action = async ({ request }: ActionFunctionArgs) => {
const { subTopic } = await authenticate.webhook(request);
return new Response();
};