Standard storefront actions
Standard storefront actions are async functions on Shopify.actions that apps and agents call to trigger theme behaviors, such as adding to cart, opening the cart drawer, or fetching the current cart. The theme decides how to handle each call, so the caller doesn't need to know whether the theme renders a cart drawer, a cart page, or another UI.
Shopify provides a default implementation for every action. Themes override the defaults to replace the default behavior with their own UI updates.
Standard storefront events fire automatically when a configured action succeeds.
Anchor to How actions are loadedHow actions are loaded
Shopify injects the actions script on every Liquid storefront, so themes don't need to add a <script> tag. After the page loads, actions are available on window.Shopify.actions with default Storefront API-based handlers.
Anchor to Calling actionsCalling actions
Call actions on Shopify.actions. The promise resolves with the result whether the theme has configured the action or not:
To check whether an action has been configured by the theme, call isDefault():
Anchor to Configuring actionsConfiguring actions
Configuring an action replaces the default handler with the theme's own behavior, such as opening a cart drawer or updating a counter in place.
getCart is intentionally not configurable. Calling Shopify.actions.getCart.configure(...) is a TypeScript error and a runtime TypeError.
getCart is intentionally not configurable. Calling Shopify.actions.getCart.configure(...) is a TypeScript error and a runtime TypeError.
Without a configuration, each action runs its default behavior:
updateCart: Writes to the Storefront API, then attempts an in-place cart refresh, such as acart:updateevent on Horizon-style themes or a section-render swap on Dawn-style themes, and falls back to a full page reload if neither pattern matches.openCart: Calls.open()on a<cart-drawer-component>or<cart-drawer>element if either is present, and otherwise redirects to/cart.getCart: Reads the current cart from the Storefront API without affecting the page.
Register a configuration inside a DOMContentLoaded listener placed above {{ content_for_header }} in the layout file, so that the configuration runs before any app code.
A configuration accepts two options: eventTarget and handler.
A function that returns the element from which auto-emitted events should dispatch. updateCart is the only action that auto-emits events.
The function receives a meta object with type (the full event name, such as 'shopify:cart:lines-update'). When type is 'shopify:cart:lines-update', meta also includes action ('add', 'remove', or 'update'). Use meta to route different events to different DOM elements:
Anchor to handler (optional)handler (optional)
An async function that runs in place of the default handler. It receives defaultHandler (the Storefront API implementation), payload, and options. To preserve the default behavior and add custom logic, call defaultHandler() and use its result.
If eventTarget is provided without handler, then the default Storefront API handler runs, the page reload is skipped, and auto-emitted events dispatch from the element returned by eventTarget. Use this pattern when the theme already listens for standard events to update its UI.
The example below uses both eventTarget and a custom handler that fetches and replaces section HTML, and registers an openCart configuration in the same listener:
Anchor to Preventing double UI updatesPreventing double UI updates
If a configuration re-renders the cart drawer and the theme's components also re-render when they receive shopify:cart:lines-update, then both render paths run and the UI updates twice. Use detail.source in the resolved promise to identify the source of the update and skip the second render:
Anchor to Auto-emitted eventsAuto-emitted events
When a configured action succeeds, the matching standard events fire automatically based on what changed:
| Action | Events auto-emitted |
|---|---|
updateCart | shopify:cart:lines-update (if lines changed), shopify:cart:note-update (if the note changed), shopify:cart:discount-update (if discounts changed), shopify:cart:error (if the mutation fails) |
openCart | None |
getCart | None |
Events dispatch from the element returned by eventTarget. When an action is configured, the theme doesn't need to also dispatch these events from its own code.
Anchor to Error handlingError handling
The updateCart action promise always resolves with { cart, userErrors?, warnings?, detail? }. It rejects only when the action couldn't run at all, such as a network failure or malformed payload.
A userErrors array indicates the mutation was rejected and cart state didn't change for the input. Common Storefront API codes include INVALID (for a malformed input) and MAXIMUM_EXCEEDED (for a quantity above the item's maximum). See CartErrorCode for the full list.
A warnings array indicates the mutation succeeded but with caveats worth surfacing. The cart did mutate. Common Storefront API codes include MERCHANDISE_OUT_OF_STOCK for a line whose merchandise is now out of stock and DISCOUNT_NOT_FOUND for an unknown discount code. See CartWarningCode for the full list.
Check userErrors and warnings before using cart:
Apps and override handlers consume the result with this shape regardless of whether the default Storefront API handler ran or a configured handler did.
Anchor to getCartget Cart
Action: Shopify.actions.getCart(payload?, options?)
Retrieves the current cart from the Storefront API, or null if no cart exists. The cartId argument is optional and auto-detected from the cart cookie when omitted. Multiple concurrent calls reuse the same in-flight request.
Returns: Promise<{ cart | null }> where cart is a subset of the Storefront API Cart object.
Triggers: no events.
Pass { signal: abortController.signal } as a second argument to cancel the in-flight request.
Anchor to updateCartupdate Cart
Action: Shopify.actions.updateCart(payload, options?)
Adds, removes, or updates cart lines. Also handles notes and discount codes. Creates a cart if none exists.
Line shapes:
- To add a new item, pass
merchandiseIdandquantity. - To update an existing line, pass the line's
idand the newquantity. - To remove a line, pass the line's
idwithquantity: 0.
Returns: Promise<{ cart, userErrors?, warnings? }>.
Triggers: shopify:cart:lines-update (if lines changed), shopify:cart:note-update (if the note changed), and shopify:cart:discount-update (if discount codes changed).
You can pass options as a second argument. It can include:
signal: anAbortSignalthat cancels the underlying request.event.detail: an object added to thedetailfield of any auto-emitted events.event.context: sets thecontextfield of any auto-emittedcart:lines-updateorcart:note-updateevents. Accepts'product','cart','dialog', or'standard-action'. Defaults to'standard-action'.
Anchor to openCartopen Cart
Action: Shopify.actions.openCart()
Requests that the theme display the cart UI. The default opens a <cart-drawer-component> or <cart-drawer> element if either is present, and otherwise redirects to /cart. Themes configure this action to open a drawer or modal.
Returns: Promise<void>.
Triggers: no events.
Configure example: