The successor to Classic Webhooks. Your app specifies which changes to receive (triggers), what data to include in the payload (GraphQL query), and delivery conditions (query_filter). The change details, affected IDs, and query results all arrive together, so you no longer need extra API calls or diff calculations after receipt.
Receive notification → fetch the collection's product list → compare against your saved list → update the app.All of this work was neededjust to identify a single change.
Declare "the changes you care about" and "the data you need" in your subscription. The delivered payload is all you need to finish processing — no extra API calls after receipt.
Subscriptions are written directly in the app's shopify.app.toml . Each event is made up of the following three elements.
Example: a product is added to or removed from a collection, or a variant's price changes.
Write a GraphQL Admin API query, and its result is included in the payload. You can also include related data and metafields.
Example: limit delivery to products with status ACTIVE only.
query_filter : no concrete syntax example is provided in this article.Scenario: your app maintains a search index, andwhenever a product is added to or removed from a collection,you want to update it.collection.products is used as the trigger, and the collection ID and product ID are passed straight into the query variables.
[events] api_version = "2026-10" [[events.subscription]] handle = "collection-membership" topic = "Collection" actions = ["update"] triggers = ["collection.products"] uri = "/api/events/collections" query = """ query CollectionMembership($collectionId: ID!, $productsId: ID!) { collection(id: $collectionId) { id hasProduct(id: $productsId) } } """
{
"topic": "Collection",
"action": "update",
"handle": "collection-membership",
"data": {
"collection": {
"id": "gid://shopify/Collection/123",
"hasProduct": true
}
},
"fields_changed": {
"added": [
"collection[id: 'gid://shopify/Collection/123'].products[id: 'gid://shopify/Product/456']"
],
"updated": [],
"removed": []
},
"query_variables": {
"collectionId": "gid://shopify/Collection/123",
"productsId": "gid://shopify/Product/456"
}
}
Adding a product changes the collection's membership, so the event is update .
The query has already run as part of the subscription. No follow-up API calls or fetching the full product list are needed.
shows "what changed." In this example, added has one entry.
You get the collection ID and product ID directly.
fields_changed. The current context includes data as appropriate. More examples are in the official delivery structure guide .The developer preview started with Product and Customer, and GA expands coverage to the major Admin GraphQL types.
Product / Collection
Customer / Company
Order / FulfillmentOrder / Refund / Return
InventoryItem / InventoryShipment / InventoryTransfer / Location
Article / Blog / Page
MetafieldDefinition / Metaobject / MetaobjectDefinition
| Aspect | Classic Webhooks | Next Gen Events |
|---|---|---|
| Change granularity | Per topic | Specified via trigger e.g.: collection.products |
| Payload contents | Fixed | Freely defined in GraphQL Can include related data and metafields |
| Delivery filtering | Not specified | query_filter decides whether to deliver based on the result |
| What changed | App fetches and compares data to identify it | fields_changed Provided in |
| Where it's configured | Not specified | shopify.app.toml in [events] |
| Going forward | Existing integrationscontinue to work | GA in 2026-10. Both can be used in the same app |
This article doesn't say when Classic Webhooks will be deprecated.
You get familiar data, but you also carry over the processing your app used to do. In the collection example, loading every product each time doesn't help you handle the change. It only adds load.
In the collection example, you only need the affected memberships. Shape the trigger and query around that.
First, identify workflows that receive high volumes and discard most of them, or that make an extra API call every time. Look at what each handler actually does and which changes and data it uses. That's your starting point for subscriptions. See the migration guide.
With Shopify CLI 4.83 or later, follow the getting started guide. Set the events API version to 2026-10 and pick the topics and triggers you need from the reference.
Update the events API version to unstable → 2026-10 (including any per-subscription overrides). Review the versioned topic reference, and test before deploying.
[events] and [[events.subscription]] : define handle / topic / actions / triggers / uri / query in them. They're deployed as part of your app configuration.
The fields that detect a change and the data you fetch don't have to be the same.query_filter looks at the queryresultsto decide whether to deliver.
The fact of the change is in fields_changed, while the current state is in data. Design your handlers so they don't confuse the two.
Querying "everything" can hit the limit. Before release, confirm your queries stay within it. Also note that triggers, variables, and scopes differ by topic.
Classic Webhooks and Events can be used together in the same app.Measure (delivery volume, payload size, number of additional API calls) → migrate one workflow at a timeis the officially recommended approach. If you used the preview, watch out for per-subscription unstable overrides that you forgot to update.
Collection topic, use collection.products as the trigger, and configure a query that returns onlyhasProduct . Update the index one item at a time usingfields_changed and query_variables .data reflects the state at execution time, so use fields_changed.added / removed to tell whether it was an addition or a removal.Order / FulfillmentOrder / Refund / Return / InventoryItem / Location and similar topics, put only the fields your integration uses in the query, and usequery_filter to exclude irrelevant events before delivery.api_version = "2026-10". If you used the preview, also update any per-subscription overrides.