doc-site
Reference

Cart events

Every event name the mini-cart emits or listens for, and what each payload carries.

Cart events

All names are defined in src/entrypoints/mini-cart/internals/core.ts as the CartEvents constant. They are dispatched as CustomEvent on window, so any script on the page can listen or dispatch without importing anything.

Payload types are in the CartEventDetailMap interface in the same file.

Regenerate this page

sed -n '/export const CartEvents/,/} as const/p' \
  src/entrypoints/mini-cart/internals/core.ts

Listening for cart changes

cart:changed fires after every successful change of any kind and carries the authoritative cart from Shopify.

window.addEventListener('cart:changed', (e) => {
  console.log(e.detail.cart.item_count, e.detail.reason);
});

reason is one of add, change, update, clear or get.

cart:changed:debounced fires 250 milliseconds after the last change. Use it instead when rendering is expensive, so a burst of quantity clicks produces one render.

Commands you can dispatch

Dispatching one of these makes the mini-cart perform the action, with the same queueing and stale-key recovery its own controls get.

EventPayload
mini-cart:getnone
mini-cart:addAddToCartPayload
mini-cart:changeChangeLinePayload
mini-cart:updateUpdateCartPayload
mini-cart:clearnone
window.dispatchEvent(
  new CustomEvent('mini-cart:add', {
    detail: { items: [{ id: 123456789, quantity: 1 }] },
  }),
);

Lifecycle events

Each action emits a start event, then either success or error.

EventPayload
cart:add:startAddToCartPayload
cart:add:success{ payload, cart }
cart:add:error{ payload, error }
cart:change:startChangeLinePayload
cart:change:success{ payload, cart }
cart:change:error{ payload, error }
cart:update:startUpdateCartPayload
cart:update:success{ payload, cart }
cart:update:error{ payload, error }
cart:clear:startnone
cart:clear:success{ cart? }
cart:clear:error{ error }

cart:clear:success can arrive without a cart, because an interceptor can observe a clear it did not perform. Treat cart as optional there.

Change events

EventPayload
cart:changed{ cart, reason? }
cart:changed:debounced{ cart, reason? }

Request events

EventPayload
cart:request{ endpoint, method, payload? }
cart:response{ endpoint, method, cart }
cart:error{ endpoint, method, error }

Fetch interceptor events

These report raw fetch activity against cart URLs, including requests the mini-cart did not make.

EventPayload
cart:fetch:request{ url, method, init? }
cart:fetch:response{ url, method, status, data }
cart:fetch:error{ url, method, error }

Request and response emission is off by default, because other apps make a large number of cart requests and the noise is not useful. Turn it on by constructing CartFetchInterceptor with { emitRequest: true, emitResponse: true }.

UI events

EventPayloadDirection
mini-cart:ui:opennoneAsk the drawer to open
mini-cart:ui:closenoneAsk the drawer to close
mini-cart:ui:update{ action }Ask for an arbitrary UI action
mini-cart:ui:openednoneThe drawer has opened
mini-cart:ui:closednoneThe drawer has closed

open asks the drawer to open, and opened reports that it has. Listening to open when you meant opened runs your code before the drawer is on screen.

Lifecycle marker

EventPayload
mini-cart:readynone

mini-cart:ready fires once the root element has wired its subsystems. Code inside the drawer should use parentMiniCart.execOnReady(...) rather than listening for this, because that handles the case where the element connects after the root is already ready.

The X-Source header

CartService sends X-Source: mini-cart on every request it makes, and CartFetchInterceptor skips any response carrying it.

Without that guard the interceptor would observe the mini-cart's own writes and emit every event twice. If you write code that calls the Ajax Cart directly and you want the drawer to notice, do not send the header. If you want to suppress the events, send it.

Design and reasoning are in Mini-cart.

On this page