---
title: Call actions
description: >-
  Call standard storefront actions from an app, an AI agent, or your own theme
  code to read and change the cart.
source_url:
  html: 'https://shopify.dev/docs/api/storefront-events-and-actions/actions/call'
  md: 'https://shopify.dev/docs/api/storefront-events-and-actions/actions/call.md'
api_name: storefront-events-and-actions
---

# Call actions

Actions are functions on `window.Shopify.actions` that work on the cart. [`getCart`](https://shopify.dev/docs/api/storefront-events-and-actions/actions/get-cart) reads it, [`updateCart`](https://shopify.dev/docs/api/storefront-events-and-actions/actions/update-cart) changes lines, the note, and discount codes, and [`openCart`](https://shopify.dev/docs/api/storefront-events-and-actions/actions/open-cart) shows it to the buyer. Every Liquid storefront includes all three, with nothing to install.

The storefront decides what each call does, so an app can add an item to the cart without knowing whether that cart is a drawer or a page. That difference stays on the storefront's side, and your calling code is the same whichever way it renders the cart.

***

## Making a call

Every call goes through `Shopify.actions` and returns a promise:

```javascript
const { cart } = await Shopify.actions.getCart();
```

Actions are ready after `DOMContentLoaded` fires. Shopify loads the runtime as a module script, and browsers run those only after the HTML finishes parsing, so an earlier call finds `Shopify.actions` undefined and throws a `TypeError`.

A call that would otherwise run at page load goes inside a listener:

```javascript
document.addEventListener('DOMContentLoaded', async () => {
  const { cart } = await Shopify.actions.getCart();
});
```

***

## Reading the result

Each action resolves differently. `openCart` resolves with nothing, `getCart` resolves with the cart, and `updateCart` resolves with the cart, adding `userErrors` and `warnings` when there are any.

The arrays exist because the cart can reject a change without the call failing. The promise rejects only when the action couldn't run at all, such as a network failure or a malformed payload.

A `userError` means the change didn't apply, so the example below stops there. A `warning` means it applied with an adjustment, like a line capped at the stock available, so the example shows the message and carries on:

```javascript
const { cart, userErrors, warnings } = await Shopify.actions.updateCart({
  lines: [{ merchandiseId: 'gid://shopify/ProductVariant/123', quantity: 1 }],
});


if (userErrors?.length) {
  showMessage(userErrors[0].message);
  return;
}


if (warnings?.length) {
  showMessage(warnings[0].message);
}


updateCartCount(cart.totalQuantity);
```

#### Result

* **cart**

  **CartSummary**

  **required**

  The cart after the update, including `lines`, `cost`, and `totalQuantity`.

* **user​Errors**

  **CartMutationUserError\[]**

  Present when the mutation was rejected. The cart stayed as it was for that input. Each entry has a `message`, and usually a code from [`CartErrorCode`](https://shopify.dev/docs/api/storefront/latest/enums/CartErrorCode) and the `field` that caused it.

* **warnings**

  **CartMutationWarning\[]**

  Present when the mutation succeeded but returned non-blocking warnings. The cart did change. Each entry has a `message`, and usually a code from [`CartWarningCode`](https://shopify.dev/docs/api/storefront/latest/enums/CartWarningCode).

* **detail**

  **Record\<string, unknown>**

  Custom data attached by the storefront's handler, used to tell one update path from another.

### CartSummary

A cart, as actions report it.

* id

  The cart GID.

  ```ts
  string
  ```

* totalQuantity

  The total number of items across every line.

  ```ts
  number
  ```

* cost

  The cart cost.

  ```ts
  CartCost
  ```

* lines

  The lines in the cart.

  ```ts
  CartLine[]
  ```

* discountCodes

  The discount codes on the cart.

  ```ts
  CartDiscountCode[]
  ```

### CartCost

The cost of a cart or a cart line.

* totalAmount

  The total amount.

  ```ts
  Price
  ```

### Price

An amount with its currency.

* amount

  A decimal money amount, such as \`29.99\`.

  ```ts
  string
  ```

* currencyCode

  The three-letter currency code, such as \`USD\`.

  ```ts
  string
  ```

### CartLine

A single line in the cart.

* id

  The cart line ID.

  ```ts
  string
  ```

* quantity

  The quantity for the line.

  ```ts
  number
  ```

* cost

  The line cost.

  ```ts
  CartCost
  ```

### CartDiscountCode

A discount code on the cart.

* applicable

  Whether the cart accepted the code.

  ```ts
  boolean
  ```

* code

  The code as the buyer entered it.

  ```ts
  string
  ```

### CartMutationUserError

A validation error returned by a cart mutation.

* code

  A machine-readable error code, such as \`INVALID\` for a malformed input or \`MAXIMUM\_EXCEEDED\` for a quantity above the item's maximum. See \[\`CartErrorCode\`]\(/docs/api/storefront/latest/enums/CartErrorCode) for the full list.

  ```ts
  string
  ```

* field

  The path to the field that caused the error.

  ```ts
  string[]
  ```

* message

  A human-readable message.

  ```ts
  string
  ```

### CartMutationWarning

A non-blocking warning returned by a cart mutation.

* code

  A machine-readable warning code, such as \`MERCHANDISE\_OUT\_OF\_STOCK\` for a line whose merchandise ran out or \`MERCHANDISE\_NOT\_ENOUGH\_STOCK\` when only part of the requested quantity is available. See \[\`CartWarningCode\`]\(/docs/api/storefront/latest/enums/CartWarningCode) for the full list.

  ```ts
  string
  ```

* message

  A human-readable message.

  ```ts
  string
  ```

* target

  The cart line or field the warning applies to.

  ```ts
  string
  ```

A storefront can replace what `updateCart` does with its own [handler](https://shopify.dev/docs/api/storefront-events-and-actions/actions/configure#handler). That handler is expected to resolve with this same shape, so your code doesn't need to know whether it ran.

***

## Checking whether a storefront configured an action

A storefront that configures an action updates its UI in place. Without a configuration, [the default](https://shopify.dev/docs/api/storefront-events-and-actions/actions/configure#how-the-defaults-recognize-a-theme) refreshes the cart itself where it recognizes how the storefront renders it, and falls back to a full page reload where it doesn't. A reload throws away scroll position and anything the buyer had typed.

`isDefault()` returns `true` while an action is still running Shopify's default, so you can check before you call:

```javascript
if (!Shopify.actions.updateCart.isDefault()) {
  // The storefront has configured this action.
}
```

***

## Adding context to emitted events

Storefront components react to [cart events](https://shopify.dev/docs/api/storefront-events-and-actions/events) without knowing what caused them. An update from your app reaches them looking the same as a buyer clicking add to cart.

You can label the events your call emits with the `event` option, so a listener can tell your change from a buyer's. This `detail` is attached to the emitted events. A separate `detail` can come back on the result, set by the storefront's [handler](https://shopify.dev/docs/api/storefront-events-and-actions/actions/configure#handler):

```javascript
await Shopify.actions.updateCart(
  { lines: [{ merchandiseId: variantId, quantity: 1 }] },
  { event: { context: 'product', detail: { source: 's-product-form' } } },
);
```

#### event

* **context**

  **'product' | 'cart' | 'dialog' | 'standard-action'**

  Where the change came from. Sets the `context` field on the emitted `shopify:cart:lines-update` and `shopify:cart:note-update` events, and defaults to `standard-action`.

* **detail**

  **Record\<string, unknown>**

  Custom data attached to the emitted events, which listeners read from the event.

***

## Canceling a request

When a buyer changes a quantity twice in a row, the first result is out of date before it lands. You can cancel that request with an `AbortSignal`:

```javascript
let controller;


async function setQuantity(lineId, quantity) {
  controller?.abort();
  controller = new AbortController();


  return Shopify.actions.updateCart(
    { lines: [{ id: lineId, quantity }] },
    { signal: controller.signal },
  );
}
```

An aborted call rejects, so catch that separately from a real failure. `getCart` takes a signal too, but concurrent reads share one request, so aborting yours ends your wait without cancelling anyone else's.

***

## Next steps

[Actions reference\
\
](https://shopify.dev/docs/api/storefront-events-and-actions/actions)

[Look up the parameters and resolved value for every action.](https://shopify.dev/docs/api/storefront-events-and-actions/actions)

[Standard events inspector\
\
](https://shopify.dev/docs/api/shopify-cli/theme/theme-dev#flags-propertydetail-standardeventsinspector)

[Call actions by hand and read their results before you build a caller.](https://shopify.dev/docs/api/shopify-cli/theme/theme-dev#flags-propertydetail-standardeventsinspector)

***
