RFC: Standardized Storefront DOM Event Payloads #2002
Replies: 11 comments 40 replies
-
|
Hello, Thanks a lot for this, that's awesome and something that should have been done years ago (but better later than never!). The set of events sound nice to me. I would however add the following:
One important thing is that themes should be required to use those events as well. One very common use case for apps is that they have their own "Add to cart" button and want to be able to open the theme cart drawer. This means that not only theme dev, but also app dev should use those events and trigger them, and themes must listen to those events instead of their own one. One extra question: how exactly the trigger would work? In the example you gave: const event = new ProductViewEvent({
product: productObject,
context: 'search'
});Does this mean it is the responsability of the theme/app dev to send the productObject? How can you guarantee that all the payload is properly set? |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @stephanie-shopify — I'm thrilled to see some standardization here. Zooming out a bit, I am unsure who emits the events. Like @bakura10, I currently emit a subset of these. These look like events that Shopify could emit — nearly everything is a form submission or a pageload. I also see the The case @bakura10 mentioned above is surprisingly tricky. When an app adds to the cart, the cart needs to open. Why this is hard:
I honestly don't have a solution for this "direction" thing. These are my best ideas so far:
The directionality problem is tricky. As a theme developer, it's unclear what I should do when |
Beta Was this translation helpful? Give feedback.
-
|
Really happy to see this, I think the Event Naming Convention needs to include an additional prefix however i.e. 'shopify:product:view' because theme devs like myself have already dispatched our own events with the same naming conventions, with the different payloads this would be a breaking change. |
Beta Was this translation helpful? Give feedback.
-
|
I'm 100% for consistency in shopify outputs, but how many frontend devs are never gonna see this because this is a server technology repo. Besides as an initial gauge*, is there any deeper reason for using the liquid repo though for shopify DX? Like is there some unmentioned tight coupling coming to liquid itself based on conventions around the shopify owned ajax api. *versus making .dev forum RFC, or the storefronts repo. |
Beta Was this translation helpful? Give feedback.
-
|
Love this - especially the event timing for things like |
Beta Was this translation helpful? Give feedback.
-
|
Grateful to see some proper RFC on this topic :) Don't hesitate to do these more frequently, we can't get enough ! I think it's a solid and welcome start. There is definitely a need and there are real challenges along the way. As a consequence, I would advise not to rush implementation and start by recommending payload versioning, not to fall into backward compatibility paralysis ! Versioning following other APIs would be coherent in my opinion. Regarding the list of events available, while I would recommend to focus on a limited set during the planning phase (
Namespacing is also a good recommendation, something simple like For the problems highlighted by @bakura10 and @gideonb, mostly regarding add to cart UI consequences, I would maybe recommend defining the const event = new CartUpdateEvent({
cartLines: [...],
action: 'add',
context: ['upsell', 'quickview', 'product_page'],
detail: {...}
});In this example, the intent would be to add an Regarding the UI consequences of some actions (adding to cart, applying filters ...), I think creating a standard reflected in theme settings could be a way to bridge the gap between theme and app developers, here's an example: // settings_data.json extract
{
"add_to_cart_ui_hint": "cart_page" | "cart_drawer" | "notification"
}
const event = new CartUpdateEvent({
cartLines: [...],
action: 'add',
context: [...],
uiHint: Shopify.theme.AddToCartUiHint // settings_data value
detail: {...}
});Not totally sure on this but if main patterns can be explicited, app developers could hook on that to update the event payload, leading to the correct UI consequence, independently of the theme. There are risks to discourage new patterns on the theme store if the structure becomes too rigid, so I'm not sure how to find the right balance on this. Also, on a more technical aspect, what about bubbling and propagation, will this be evaluated on a per event basis, can this be overriden ? Also, for cart update operations and many other actions, many specifics and context-dependent factors are to take into account, so the system would need to be extensible for developers but standardized on the basic level to be theme-agnostic and usable at the most basic level (add to cart from product page). This RFC and the events are clearly geared towards themes for now, but what about extensibility (user events are in the initial RFC after all), is there a strategy of adopting them there as well, maybe have standardized checkout events as well ? Is this in the global scope, who has the responsibility of sending these ? Lots of suggestions, on which I can add to extensively integrate partners on the error, testing and validation aspects of this central feature, which are absent from this early RFC but will be important later down the road. Hope this has been helpful, good work launching RFC, we need more of them ! |
Beta Was this translation helpful? Give feedback.
-
|
I have not seen Market properties mentioned yet. It's a really needed for marketing attributing across regions |
Beta Was this translation helpful? Give feedback.
-
|
I've now reviewed the properties and.. cart:view cart:attribute-update cart:update product:select |
Beta Was this translation helpful? Give feedback.
-
|
Hello. Why not just expose the existing standardized analytics events to the front-end? The lack of this feature caused us to create a custom pixel that just pipes these events to the main window, and then we handled them in an app-embed block anyways; since a lot of tracking pixels (e.g. FB, Google, Bing) require direct access to the top-level DOM (i.e. neither custom pixels nor app pixels worked). Or create a type of pixel that's allowed to run in the main window context + checkout. Right now getting consistent event handling everywhere requires a mix of solutions depending on access to the main window context and to analytics events (i.e. only pixels in checkout, which can't render in the main DOM, and the requirement for a custom pixel that passes events to the main window for an app embed block so it can both access the main window and receive analytics events). |
Beta Was this translation helpful? Give feedback.
-
|
Hi, I'm a bundle app developer and I have integrated with more than 15 cart drawers from various apps and themes. There are a few things I want to mention. Theme or app developers may act as the event creator and consumer at the same time. They may not only act as a single role. If you define the theme or app developer to act as a role, this is not appropriate. My use case is mostly related to adding a bundle to cart. Other bundle apps may have a similar workflow:
Here are the event listeners and triggers defined by some themes. Your team might read these docs before: https://support.maestrooo.com/article/764-javascript-events-exposed-by-the-theme |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for putting together this proposal. Standardizing storefront DOM event payloads is a huge step forward for improving interoperability between themes, apps, and analytics solutions. From the perspective of app developers which have intents that they also wish to publish for other interactions to latch on to
These events should follow the same structure as the existing ones, with a payload that includes product, selectedVariant, and customer objects, and a context to identify the source (product page, collection page, or quick-view modal). Also we are happy to collaborate on this in anyway with the team at shopify - since we do hold a significant number of merchants (48K+) to test run these events for
This would help event consumers understand where an interaction occurred without inferring it from URL or DOM structure. That distinction is often important for engagement apps that adapt UI behavior depending on context.
I was also curious if these events will be available only for newer themes or should we expect this consistency across all themes? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Author: Shopify
Expected end date: November 3, 2025
This RFC proposes patterns and payload structures for standardized storefront DOM events. To enhance developer experience and improve storefront performance, we recommend including a curated subset of essential object data directly in event payloads.
As we introduce new standard DOM events for storefronts, a critical question is what data should be included in the event payload. The decision directly impacts both app developers and storefront performance.
If we only emit resource IDs (e.g.,
productId), every consuming app will likely make an immediate Storefront API call to fetch the object's details. These calls will likely be redundant and all at the same time.Conversely, we must be careful not to include too much data, as this can also negatively impact performance by requiring the theme to render large objects in Liquid, much of which may go unused. We'd like to find the right balance, making events useful for developers without compromising the performance of the merchant's storefront.
The goal is to provide enough data to cover ~80% of common use cases out-of-the-box. This approach aims to avoid performance issues while still empowering developers, and it serves as the basis for gathering community feedback before final implementation.
1. Problem
As we introduce new standard DOM events for storefronts, we need to determine what data should be included in event payloads. This decision directly impacts both app developers and storefront performance.
Challenges:
We need to find the right balance, making events useful for developers without compromising merchant storefront performance.
2. Proposal
We propose events include a predefined, essential subset of the primary object's data directly in the event payload (e.g.,
event.product.id,event.product.title,event.product.price).The goal is to provide enough data to cover ~80% of common use cases, allowing developers to immediately use the event without a follow-up API call. For the remaining, more specialized use cases that require fields not present in the payload, developers can use the provided IDs to query the Storefront API for additional information. Additionally, theme developers can choose to include extra information under
event.detail.This approach strikes a practical balance between the performance cost of fetching data and the developer experience benefits of having rich, contextual data readily available.
2.1. Design Patterns
To ensure our events are consistent, easy to use, and extensible, we will follow a clear set of design patterns.
Event Naming Convention
Event names will follow a simple and predictable
category:actionstructure in present tense. This makes events easy to discover and understand.Examples:
product:viewsearch:submituser:sign-outEvent payloads will be modeled after the GraphQL Storefront API where possible, using
camelCasenaming for properties and including a curated set of nested objects for essential context. For example:event.product.titleEvent Creation and Consumption
To simplify emitting events, we will provide helper classes for theme developers. For consumers (app developers), these are standard browser events that can be listened to with plain JavaScript, requiring no special libraries.
Note: The delivery method of these classes is still to be determined (global classes or a module with import maps).
Creation (for Theme Developers):
Consumption (for App Developers):
Standard and Custom Payloads
Each event helper class will accept a set of standard properties (e.g.,
context,product,cart) which are then made available under the event object directly. For custom use cases, theme developers can pass arbitrary data under adetailproperty.Context for Granularity
To reduce the total number of event names and provide more granular insight, we propose an
event.contextproperty. This helps distinguish where a common action originated.For example, a
product:viewevent could be emitted from multiple places. Thecontextproperty clarifies the source without needing separate events:Event Timing
While event timing is specific to each action, we propose a pattern for asynchronous operations like updating the cart. For these events, we will dispatch them immediately, before the async action starts.
The payload will include a
promisethat mirrors the action's lifecycle, giving developers the flexibility to run code before and after the action.2.2. Common Objects
Event payloads will reference standard Storefront API object types. Note that not every property in these objects need to be available in the events but they are a general reference:
When a property type is defined in one event, the following events assume the same type for similar properties unless stated otherwise.
2.3. Event Specifications
The following contains a list of events with their proposed properties based on the GraphQL Storefront API. The use cases listed are examples of how these events will be used by consumers so that we cover the most typical scenarios.
Page Events
page:viewAny page or route is viewed.
Properties:
pagetemplateThe template/type of the page. For example, “product” or “index”.urlFull URL of the page.titleDesired title. It doesn’t need to match the tab title.Product Events
product:viewProduct becomes visible (page, search, collection, ad).
Properties
contextpage | search | collection | dialog | recommendationproductidtitlehandleselectedOrFirstAvailableVariantidtitleavailableForSalepriceMoneyV2selectedOptionsArray of SelectedOptionproduct:selectProduct variant is selected.
Properties
variantidtitleavailableForSaleselectedOptions- Array of SelectedOptionprice- MoneyV2productidtitlehandleCart events
cart:viewCart is viewed either in a modal or a full page.
Properties
contextpage | dialogcartidtotalQuantitycostsubset of CartCost fieldstotalAmountMoneyV2lines[]Array of subsets of CartLineidquantitycostdiscountCodes[]Array of CartDiscountCodecart:lines-updateItems modified in cart
Use cases
Properties
cartLines[]Array of subsets of CartLineidquantityactionadd | remove | updatepromiseResolves to:cartidtotalQuantitycostsubset of CartCost fieldstotalAmountMoneyV2lines[]Array of subsets of CartLineidquantitycostcart:errorWhen cart mutation returns an error
Properties
errorcodecart:discount-updateDiscount code applied.
Properties
cartidtotalQuantitycostsubset of CartCost fieldstotalAmountMoneyV2discountCodes[]Array of CartDiscountCodeSearch & discovery events
search:submitSearch is submitted.
Use cases
Properties
searchqueryproductFilters?Array of ProductFiltersortKey?SearchSortKeyscontextheader | page | dialogpromiseResolves to:totalCountsearch:updateSearch filters/sort change
Properties
searchqueryproductFilters?Array of ProductFiltersortKey?SearchSortKeyspromiseResolves to:totalCountCollection events
collection:viewCollection is viewed
Use cases
Properties
collectionSubset of Collection objectidhandleproductCountcollection:updateCollection filters/sort change.
Properties
collectionidproductCountfilterssortUser events
user:sign-inUser signs in
Properties
method:email | social | shopuser:sign-outUser signs out
Properties
sessionDurationuser:updateUser profile updated
Properties
fields[]String arraycontext:profile | checkoutConsent events
consent:updateConsent preferences change
Properties
accepted_categoriesArray of analytics | marketing | personalizationrejected_categoriesArray of analytics | marketing | personalizationactionaccept-all | reject-all | accept-somecontextbanner | preferencesconsent:viewConsent UI viewed
Properties
context:banner | preferences3. Feedback Requested
We are seeking feedback from the developer community on:
Payload completeness: Do the proposed payloads cover your common use cases? What fields are missing that you would frequently need?
Payload size: Are we including too much or too little data in any of the events?
Event naming: Are the event names intuitive and discoverable?
Design patterns: Do the proposed patterns (context property, promise for async operations, custom detail field) meet your needs?
Open questions: Input on any of the open questions listed above
Additional events: Are there important events missing from this specification?
Beta Was this translation helpful? Give feedback.
All reactions