Skip to main content

Create an Events subscription

Suppose you're building an app that keeps a merchant's external product catalog in sync with Shopify. The external catalog already exists. Your app's job is to reflect changes as they happen.

When a product is created in Shopify, your app needs to add it to the external catalog. When it's deleted, your app needs to remove it. When a variant's price or compare-at price changes, your app needs to patch the corresponding record. In this tutorial, you'll set up Events subscriptions for all three actions.

Developer preview

Events is in developer preview on the unstable API version, available today for a subset of topics. Use it for early testing ahead of a stable release and broader topic coverage. For topics not yet supported, use webhooks alongside Events in the same shopify.app.toml. As Events expands topic coverage, it will become the primary subscription mechanism.

In this tutorial, you'll learn how to do the following tasks:

  • Write Events subscriptions for create, delete, and update actions.
  • Use triggers and a custom query to receive only the data you need.
  • Handle deliveries in route handlers, and use fields_changed and query_variables to process those deliveries.

Requirements

Shopify CLI version 3.92 or higher

Events require Shopify CLI version 3.92 or higher. Run shopify version to check, and see upgrade instructions if needed.

Scaffold an app

Scaffold an app that uses the React Router template.

Anchor to Subscribe to product EventsSubscribe to product Events

Configure subscriptions in shopify.app.toml, define a route to receive deliveries, and process the payload in your handler. You'll start with create and delete, then add an update subscription that narrows what's delivered with triggers, query, and query_filter.

Anchor to Configure top-level propertiesConfigure top-level properties

Before you add subscriptions, set the access scope your topic requires and pin the Events API version.

Anchor to Update your access scopesUpdate your access scopes

Events topics require scopes. Because you're subscribing to Product topic changes, include the read_products scope in the configuration file.

Add an [events] block and pin api_version to unstable. Events is only available on the unstable API version while it's in developer preview.

Anchor to Subscribe to product creates and deletesSubscribe to product creates and deletes

Create subscriptions for create and delete actions on the Product topic, then define a single route handler that receives both.

The handler uses authenticate.webhook to verify the request and read shop, topic, and payload from the delivery.

Add an [[events.subscription]] block. The handle identifies which subscription triggered a delivery.

Set topic to the resource name, actions to the operations to listen for, and uri to the route that will receive deliveries.

Add a second [[events.subscription]] block for the Product topic with actions = ["delete"] using the same route.

Use authenticate.webhook from your app's shopify.server module. Shopify's library validates the request and gives you shop, topic, and payload. Log one short line and the full payload so you can inspect it in the terminal where shopify app dev is running.

All subscriptions in this tutorial will reuse this same endpoint.

If you're not using the React Router template, you'll need to verify HMAC signatures yourself. See Verify Events deliveries for the raw verification approach.

Anchor to Subscribe to product updatesSubscribe to product updates

Create another subscription to receive updates for specific field changes, not just create and delete actions. You'll add triggers to narrow deliveries to variant price and compare-at price changes, a query to fetch exactly the data your sync needs, and a query_filter to suppress deliveries for inactive products.

Anchor to Define the subscriptionDefine the subscription

Add a new [[events.subscription]] block for the Product topic with actions = ["update"].

Add triggers to narrow deliveries to variant-level changes your sync logic actually needs. Without triggers, every update to the product fires a delivery.

Add a query to shape the payload. When a trigger fires, Shopify executes this query and includes the result in the data field of the delivery. Without a query, the delivery has no data field.

Add query_filter to suppress deliveries for products that shouldn't be synced to the external catalog. The filter evaluates after the query runs, so you can filter on any field returned by your query.

Anchor to Process update deliveriesProcess update deliveries

Update deliveries with a configured query include fields_changed, query_variables, and data. Each field serves a different purpose in your handler.

Anchor to Read ,[object Object], to identify what triggered the deliveryRead fields_changed to identify what triggered the delivery

fields_changed is an array of field paths, each embedding the GID of the entity that changed. Use it to know which specific field and variant caused this delivery.

Anchor to Use ,[object Object], to access entity IDsUse query_variables to access entity IDs

query_variables gives you the entity IDs directly. No need to parse them from the query response or from fields_changed paths.

Anchor to Act on the query dataAct on the query data

The data field contains the response from your subscription's query. Use it to access the fields your app needs without making a follow-up API call.

Info

Queries executed by subscriptions don't count toward your rate limits but have a 250 point complexity limit.

Anchor to Test your subscriptionsTest your subscriptions

Run your app on a dev store and confirm each subscription delivers as expected.

Anchor to Set up testing on a dev storeSet up testing on a dev store

Save your TOML file and run shopify app dev. If app dev is already running, the subscription is automatically created or updated.

Navigate to your test shop and create a new product. The payload should print to your CLI.

Delete a product. Your delete endpoint should receive a delivery.

Change the price of a product variant on an active product. The payload should print to your CLI, including fields_changed, query_variables, and data.

Update the price on an inactive product, or update the title on an active product. In both cases, you don't receive a delivery.

When you're ready to release your subscriptions to production, navigate to your app directory and run the following command:

Terminal

shopify app deploy

Optionally, you can provide a name or message for the version using the --version and --message flags.

Releasing an app version replaces the current active version that's served to stores that have your app installed. It might take several minutes for app users to be upgraded to the new version.

Tip

If you want to create a version, but avoid releasing it to users, then run the deploy command with a --no-release flag. You can release the unreleased app version using Shopify CLI's release command, or through the Dev Dashboard.

Was this page helpful?