Skip to main content

Events

Subscribe to topics with field-level triggers, custom GraphQL Admin API queries, and query filters. Define subscriptions in your shopify.app.toml and receive deliveries only when the data you care about changes.

Developer preview

Events is in developer preview, available today for a subset of topics you can find in this section in the sidebar.

Use Events 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.

Use Events to subscribe to changes in merchant data and receive deliveries when they occur. With Events, you choose which GraphQL Admin field changes trigger a delivery, what data each payload contains, and whether to send the delivery at all.

Triggers and queries are independent from one another. You can query anything available in the GraphQL Admin API from within a query in response to any trigger.

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


When a qualifying change happens in a store, Shopify sends a delivery (a signed JSON notification) to your app’s endpoint. You declare a subscription in shopify.app.toml to tell Events which resource to watch, which changes should trigger a delivery, and what data each delivery includes. The four core concepts are:

  • Configuration: Declare which resource and operations to watch, and where to send deliveries.
  • Delivery filtering: Use triggers to narrow which field changes qualify, and query_filter to suppress deliveries based on current data values.
  • Delivery structure: Shape the delivered payload with a GraphQL query and understand what each delivery contains.
  • Verify deliveries: Verify HMAC signatures and ignore duplicate deliveries using Shopify-Webhook-Id.

If you’re migrating from webhooks, see how concepts map.


Events are configured directly in your shopify.app.toml. Subscriptions are defined under the [events] table, with each subscription in an [[events.subscription]] entry. Subscriptions defined in your app configuration file apply to all shops where your app is installed.

We recommend that the api_version reflects the latest supported API version.

See Manage Events subscriptions for a setup walkthrough.


Anchor to Top-level propertiesTop-level properties

The top-level table for all Events configuration contains the following properties:

api_version required

The API version used for Events subscriptions.


Anchor to Per-subscription propertiesPer-subscription properties

Each entry defines a single subscription containing the following properties:

handle required

A unique name for this subscription. The handle is included in deliveries so you can identify which subscription triggered the delivery. Alphanumeric characters, _, and - only. Maximum 50 characters.

topic required

The resource to subscribe to (for example, Product). Topics correspond to GraphQL Admin objects. Some child objects don't have a separate topic. For example, ProductVariant changes surface under the Product topic. See the sidebar for the full list of supported topics.

actions required

An array of operations to listen for. Valid values are create, update, and delete. create and delete apply to the topic entity itself. update covers changes on the topic entity and, where the model routes them there, on owned children (for example, ProductVariant fields under Product).

uri required

The endpoint URL where deliveries are sent.

triggers optional

An array of field paths that specify which update changes should trigger a delivery. triggers applies only to update actions. It has no effect on create or delete. Multiple triggers use implicit OR logic: a delivery is sent when any listed field changes. Omit to receive deliveries on any update change to the resource. For example, "product.variants.price" triggers a delivery only when a variant's price changes.

Only source-of-truth fields can be used as triggers. Calculated or derived fields (like product.description, which is derived from descriptionHtml) and auto-updated timestamps (like product.updatedAt) are not valid triggers. Deprecated fields can still be valid trigger paths. Deprecation signals eventual removal from the API but doesn't remove the underlying change signal. Refer to each topic's trigger list for available fields.

See Filter Events deliveries for field path syntax and constraints.

query optional

A GraphQL query that defines the shape of the data returned in the delivery payload's data field. Your query is not limited to the topic's root resource. You can use any query root available in the GraphQL Admin API, and you can include multiple root nodes in a single query. IDs flow upward from the changed entity through its parent hierarchy and become available as GraphQL variables. Variable names follow the $entityId pattern in camelCase (for example, $productId, $variantsId). A variant-level change provides both $variantsId and $productId; a product-level change provides only $productId. Variables used in your query must be available given your selected triggers, and Shopify validates this at subscription time. If you omit query, the payload won't include data.

Note

Shopify runs your query and includes the result in the payload. Because the query runs after the qualifying change occurs, results reflect the state of the data at query execution time, not necessarily at the time of the change.

See Events delivery structure for query examples and variable reference.

query_filter optional

A filter expression that gates delivery based on the results of your query. Deliveries are only sent when the filter matches. Supports AND and OR operators for combining conditions (for example, "product.variants.price:>100 AND product.status:'ACTIVE'"). The fields referenced in the filter must be included in your query, and filter paths must start from the same root field as your query (for example, if your query starts at productVariant, use productVariant.price in the filter, not product.variants.price). Filters evaluate against current values, not change deltas. If query_filter is set, query must also be configured.

Note

Don't include a space between : and the value in a filter expression. product.status:'ACTIVE' is valid. product.status: 'ACTIVE' (with a space after the colon) fails.

See Filter Events deliveries for filter syntax and examples.


Two mechanisms control when deliveries fire and what they contain.

  • triggers narrows which update changes qualify before any query runs. Without it, a delivery fires for any field change on the subscribed topic. Adding triggers restricts deliveries to changes on those specific field paths. Multiple paths use implicit OR logic. triggers has no effect on create or delete.
  • query_filter evaluates after the query result is ready and suppresses the delivery if the expression doesn't match. Filters evaluate against current values, not change deltas. query_filter requires query to also be configured, and filter paths must reference fields your query returns.

See Filter Events deliveries for field path syntax, filter expressions, and constraints.


Shopify delivers a JSON payload to your uri. HTTPS endpoints receive an HTTP POST with request headers. AWS EventBridge and Google Pub/Sub deliver the payload through their respective transport formats. The body always includes metadata about the change. Add a query to include custom data from the GraphQL Admin API.

Every Events delivery payload contains the following fields, depending on whether a custom query is defined:

Always present
  • topic: The resource name for this delivery (for example, Product).
  • action: The operation that occurred: create, update, or delete.
  • handle: The subscription handle from your TOML configuration, useful for routing when you have multiple subscriptions on the same topic.
  • fields_changed: An array of dot-notation paths with embedded GIDs showing exactly which fields changed and on which entities.
  • query_variables: The entity IDs that were resolved for this delivery in a flat key-value format, matching the variables available to your query.
Present only when a query is configured
  • data: The result of your GraphQL query.
  • errors: A GraphQL errors array returned when your query fails to execute (for example, referencing a removed field or a deleted resource).

Each delivery captures a single change, but fields_changed can include multiple paths when several fields changed together. Child entities like variants trigger their parent topic's delivery, so a product with many variants can generate high volume.

Use triggers to narrow which field changes fire deliveries, and query_filter to further gate what Shopify sends. When a payload exceeds the channel size limit, Shopify delivers a download URL instead.

See Large payloads for payload limits and handling guidance.

HTTPS deliveries include the following request headers (using the Shopify- prefix). Treat header names as case-insensitive in your implementation.

  • Shopify-Topic: The topic name (for example, Product).
  • Shopify-Action: The action (create, update, or delete).
  • Shopify-Handle: The subscription handle.
  • Shopify-Api-Version: The API version for this subscription.
  • Shopify-Resource-Id: The GID of the root resource.
  • Shopify-Event-Id: A unique ID shared across all deliveries produced by the same merchant action.
  • Shopify-Webhook-Id: A unique composite key per delivery, used to detect and ignore duplicate deliveries.
  • Shopify-Triggered-At: Timestamp of when Shopify triggered the delivery.
  • Shopify-Shop-Domain: The myshopify.com domain of the store that triggered the change.
  • Shopify-Hmac-Sha256: Base64-encoded HMAC-SHA256 signature (HTTPS deliveries only).

The User-Agent header is set to Shopify-Webhooks on all deliveries.

See Verify deliveries for HMAC verification steps and deduplication guidance.

Add a query to your subscription to define exactly what data each delivery contains. When set, Shopify runs the query after a qualifying change and includes the result in the payload's data field.

Your query isn't limited to the topic's root resource. You can use any query root available in the GraphQL Admin API, including child entities like productVariant directly. When a variant triggers the delivery, both $productId and $variantsId are available as variables, so you can query either or both.

The subscription uses the Product topic, but the query fetches variant data directly using productVariant as the root. If you omit query, the payload won't include data.

See Custom queries for examples with multiple query roots and a full payload walkthrough.


Every HTTPS delivery includes a Shopify-Hmac-Sha256 header containing a base64-encoded HMAC-SHA256 signature generated from the raw request body and your app's client secret. Verify this signature before processing any delivery.

To detect and ignore duplicate deliveries, use Shopify-Webhook-Id. This header is a unique composite key per delivery. Store it and check for it on each incoming request so your handler can skip reprocessing when a delivery is retried.

See Verify Events deliveries for verification steps and code examples.


Unsupported topic values fail validation when you deploy. See the sidebar for the current list of supported topics.

Events can be configured only in shopify.app.toml.



Was this page helpful?