Migrate Shopify Webhooks to Events: Triggers, Queries and Limits
To migrate Shopify webhooks to Events, start from the fact that with API version 2026-10 Events are generally available as the successor to classic webhooks. Migrating is not a find-and-replace, because the work moves from your handler into the subscription. This guide follows Shopify’s migration steps: translate the fields you read, choose what should trigger a delivery, and optimize the query to fit the 100-point limit. It also lists what Shopify says to keep on webhooks for now. Checked against Shopify’s migration guide and its October 1, 2026 announcement.

Before You Migrate Shopify Webhooks to Events
Events use the same delivery infrastructure as classic webhooks, with field-level triggers and data chosen by a GraphQL query. Your existing webhooks keep working, and you can run both in one app and move workflows over one at a time. Shopify’s migration guide lists Shopify CLI 3.92 or higher, while the general availability announcement says 4.83 or later for new apps. The two numbers disagree, so run shopify version, follow the upgrade instructions, and prefer the newer one. If you already use the developer preview, change the events API version from unstable to 2026-10, including any subscription-level overrides. For the concepts, read Shopify Events vs Webhooks first.
Pick the first workflow carefully. Shopify suggests starting where your app receives many updates, discards most of them, or makes another API call on every delivery.
Step 1: Translate the Webhook Fields You Read
Shopify’s guide maps each classic topic to an Events topic and gives a starter GraphQL query. REST field names generally change from snake_case to camelCase, but some fields change shape or have no equivalent. These are the differences that matter most.
admin_graphql_api_idbecomesid. Numeric REST IDs have no Events equivalent.- Flat arrays such as variants, images and line items become connections with
nodes. - Orders:
financial_statusbecomesdisplayFinancialStatus,fulfillment_statusbecomesdisplayFulfillmentStatus, and prices come back as money sets. - Products:
body_htmlbecomesbodyHtml, tags return as an array instead of a comma-separated string, andoption1tooption3becomeselectedOptions. - Enums are uppercase, for example product status
ACTIVE,DRAFTorARCHIVED.
Some fields are simply gone. Customers have no currency, and variants have no old_inventory_quantity. Audit your handler for anything that depends on these before you change a subscription. Shopify stresses that the starter queries only help with field mapping. They do not configure a subscription or reproduce the conditions that fired the classic webhook.
Step 2: Decide What Triggers the Events Delivery
A query selects data. It does not decide when the subscription fires. For each webhook you migrate, identify the change your app reacts to, then find the matching topic, action and triggers in the Events reference.
- Create: query the new resource by its ID.
- Update: every subscription whose actions include
updaterequires triggers. Choose the specific field changes your app needs. - Delete: there is no query, because the resource no longer exists. Use the identifiers in
query_variables.
For a business event such as an order becoming paid, identify both the change and the resulting state. Use triggers to detect the change and query_filter to check the current result. A query filter cannot detect a transition by itself. If your app tracks a set, subscribe to the changes that remove resources as well as the ones that add them. Split subscriptions when changes need different IDs or query roots.
Step 3: Optimize the Query
Events subscription queries have a complexity limit of 100 points. By default scalar and enum fields cost zero, object fields cost one, and connection costs depend on first and last. Shopify’s starter queries for orders and products are broad and can exceed the limit, so trim them. Keep only the fields your handler and filter need. A page size such as first: 250 limits records returned, but it is not a budget or a guarantee of a complete result.
Shopify checks complexity when you deploy an app version, without running the query. To validate without releasing, use the flag below.
shopify app deploy --no-releaseA Worked Example
An app that syncs prices needs deliveries only when a variant’s price changes on an active product. Check the Product reference for the exact trigger names before you copy this.
[events]
api_version = '2026-10'
[[events.subscription]]
handle = 'price_sync'
topic = 'Product'
actions = ['update']
triggers = ['product.variants.price', 'product.variants.compareAtPrice']
uri = '/api/events'
query = '''
query priceSync($productId: ID!, $variantsId: ID!) {
productVariant(id: $variantsId) { id price compareAtPrice sku }
product(id: $productId) { id status }
}
'''
query_filter = "product.status:'ACTIVE'"Notice that the query asks for one variant, using the child ID the trigger provides, instead of reloading every variant. Shopify recommends this: when a trigger supplies a child ID, query the changed child directly.
Which Shopify Webhooks to Keep Instead of Events
Shopify’s guide is explicit about several cases where Events do not fully replace a webhook in 2026-10.
returns/requestandreturns/approve: keep them when you need a notification per request or approval. The Events create action covers both requested and already-approved returns, so the queried status cannot reliably tell them apart.reverse_fulfillment_orders/dispose: there is no equivalent disposition trigger.orders/edited: there is no direct field-level equivalent. Start from the order update mapping and find triggers that cover the edits you need.- Tag events: the query returns the full current tag set, and a query filter cannot tell an addition from a removal. Compare with your stored state.
Our Analysis: How to Migrate Webhooks to Events
Migrate one workflow, then measure. Shopify recommends tracking deliveries received, payload size and follow-up API calls before and after. If those numbers do not drop, the subscription is probably a copy of the old payload and not a redesign.
Do not recreate the old payload. Shopify warns that copying your existing payload into a GraphQL query carries over the work your app already did. Start from what the app must do when something changes.
Treat the query result as current state. The documentation says Events queries return the state at the moment the query runs, which can differ from the state when the change happened. Use fields_changed to understand the change and data for context. Our advice is to avoid logic that assumes the two always agree.
Avoid double processing during a parallel run. If you keep a webhook and an Events subscription for the same change while you compare them, only one should act. Our suggestion is to let the old webhook act and have the new subscription log, then switch.
Keep the plumbing. Retries, authentication and deduplication still matter. Our webhook setup and debugging guide and idempotency guide still apply.
FAQ about Migrating Shopify Webhooks to Events
Will my existing webhooks stop working? No. Shopify says existing classic webhook integrations continue to work, and you can use both in one app.
Can I migrate every topic? Not yet. For topics or subscription patterns Events does not support, keep using classic webhooks. Shopify lists specific returns and fulfillment cases above.
What is the query limit? 100 complexity points per subscription query, checked when you deploy an app version.


