window.aftersell.cart.events.
Subscribing is a set-up call, so it’s safe at the top of your script, with no need to wait for ready().
Available events
Subscribing
events.on(event, handler) registers a handler and returns a function that unsubscribes it:
events.once(event, handler): fires once, then unsubscribes itself.events.off(event, handler): removes a specific handler.
The two rules
Almost every event bug traces back to one of these.Don’t change the cart from cart_updated without a guard
Changing the cart inside a cart_updated handler fires cart_updated again. If that handler changes the cart again, you have an infinite loop. The shopper watches their cart thrash while the page hammers Shopify.
Treat the payload as read-only
Every handler for one event receives the same object. Mutating it changes what the handlers after yours see, including handlers belonging to other apps on the store.registerLineTransform.
cart_loaded
Fires once, when the cart first loads on the page. The payload is the full cart object.cart_loaded is replayed to late subscribers. If you subscribe after the cart has already loaded, your handler is called immediately with the current cart. Subscription order never matters, so you don’t have to worry about whether your script beat the cart.
cart_updated
Fires every time the cart contents change after the first load, whether from the drawer, from your own actions, from the theme, or from another app. The payload is the full cart object.item_added
Fires when a new line appears in the cart. The payload is{ item }, where item is the cart line.
cart_loaded. Adding several distinct products at once fires the event once per line.
item_removed
Fires when a line disappears from the cart. The payload is{ item }, the line as it was just before it went away, so you can still read its key, variantId, and title.
item_added: lowering a quantity without hitting zero isn’t a removal.
cart_opened and cart_closed
Fire when the drawer opens and closes. No payload.checkout
Fires when the shopper clicks the checkout button, immediately before the browser navigates. No payload.Listening from outside the SDK
Every event is also dispatched as a DOMCustomEvent on window, so you can listen without touching window.aftersell.cart. That is useful from a theme file, a third-party app, or a script that loads independently of the cart.
Mind the naming: the bus uses
snake_case, the DOM events use kebab-case behind an aftersell:cart: prefix.
event.detail and matches the cart object. Events are dispatched on window, so a listener anywhere on the page receives them. The cart renders in a shadow root, but the shadow boundary is never in the event’s path. Each dispatch clones the payload, so a listener mutating event.detail can’t affect anyone else, and a listener that throws can’t disrupt the SDK.
Shopify standard cart events
Separately, the cart publishes Shopify’s standard cart events ondocument whenever it changes the cart, so theme code and other apps can react to Aftersell’s mutations the same way they react to the theme’s:
Each event also carries a
promise that Aftersell settles when the underlying write lands, matching Shopify’s standard — await it, don’t resolve it. These are dispatched on document and bubble, so a window listener receives them too.
Where to go next
- Cart object: the full shape of the payloads above.
- Actions: how to change the cart from a handler.
- Hooks: for changing how the cart renders, rather than reacting to it.
- Use cases: analytics tracking, free gifts, and other complete examples.