# Cart drawer public API (SectionStoreCart)

> JavaScript reference for developers. Open the drawer, change the cart, block actions and listen for events.

Every page where the drawer runs has a JavaScript API at `window.SectionStoreCart`. Use it to open the drawer, read or change the cart, block an action, or listen for changes. This article is for developers. You don't edit any Section Store code.

To see the reference in your browser, open your storefront, open the console and run `SectionStoreCart.help()`. The current version is **1**.

## Quick start

```js
// Wait for the first cart to load, add a product, open the drawer
await SectionStoreCart.ready;
await SectionStoreCart.addItem({ id: 40000000000000, quantity: 1 });
SectionStoreCart.open();

// React to cart changes from any source
window.addEventListener("section-store:cart:updated", (event) => {
  console.log(event.detail.cart.item_count, "items via", event.detail.source);
});

// Block checkout until the shopper accepts terms
SectionStoreCart.onBeforeCheckout(({ cart }) => cart.attributes.terms_accepted === "yes");
```

## Drawer

| Method | Returns | What it does |
| --- | --- | --- |
| `open()` | void | Opens the drawer |
| `close()` | void | Closes the drawer |
| `toggle()` | void | Opens when closed, closes when open |
| `isOpen()` | boolean | Whether the drawer is open |

## Reading the cart

| Member | Returns | What it does |
| --- | --- | --- |
| `ready` | Promise | Resolves with the API once the first cart has loaded |
| `getCart()` | cart or null | A copy of the cached Shopify cart |
| `getItemCount()` | number | Total quantity in the cart |
| `getTotalPrice()` | number | Cart total in cents |
| `refresh()` | Promise | Fetches the cart from Shopify again |
| `subscribe(fn)` | function | Calls `fn(cart)` now and on every change. Call the returned function to stop. |

## Changing the cart

Each method returns a Promise with the updated cart. The drawer redraws by itself.

| Method | What it does |
| --- | --- |
| `addItem(item)` | Adds one item. `item = { id, quantity, properties, selling_plan }`, where `id` is the variant ID. |
| `addItems(items)` | Adds several items in one request |
| `addFormData(formData)` | Adds from a product form's `FormData` |
| `updateLine(key, qty)` | Sets a line's quantity. `key` is the line's `key` from the cart. |
| `removeLine(key)` | Removes a line |
| `clear()` | Empties the cart |
| `applyDiscount(code)` | Adds a discount code. An invalid code doesn't throw. It comes back in `cart.discount_codes` with `applicable: false`. |
| `removeDiscount(code)` | Removes a discount code |
| `setNote(text)` | Sets the order note |
| `setAttributes(obj)` | Sets cart attributes. Leave `__section_store_cart_managed` alone. |

Adding through the API doesn't open the drawer. Call `open()`.

## Hooks that can cancel an action

Each hook runs before the action. Return `false` to stop it. Each one returns a function that removes it.

| Hook | Your function receives | Stops |
| --- | --- | --- |
| `onBeforeOpen(fn)` | nothing | The drawer opening |
| `onBeforeClose(fn)` | nothing | The drawer closing |
| `onBeforeAddToCart(fn)` | `{ form, formData }` | A theme product form going through the drawer |
| `onBeforeCheckout(fn)` | `{ checkoutUrl, cart }` | The checkout button |

What happens on an error or a Promise differs:

- **Open, close and add to cart:** a thrown error is logged and the action goes ahead.
- **Checkout:** a thrown error blocks checkout, and its message shows in the drawer. A returned Promise blocks it too.

While any `onBeforeCheckout` hook exists, the express checkout buttons hide. A wallet click can't be stopped.

```js
// Keep the drawer closed on the cart page
const stop = SectionStoreCart.onBeforeOpen(() => location.pathname !== "/cart");
// later: stop();
```

## Line rules

Both functions must answer synchronously. A function that returns a Promise throws "Cart integration callbacks must return synchronously".

| Method | Your function receives | It returns |
| --- | --- | --- |
| `registerLineRules(fn)` | `{ item, cart }` | `{ allowRemove, allowQuantityChange }` or undefined |
| `onBeforeUpdateLines(fn)` | `{ cart, updates }` | Updates with linked line quantities, `false`, or undefined |

- `registerLineRules` locks a line's controls. A rule that fails locks its line.
- `onBeforeUpdateLines` can add linked changes. It must keep the updates it received. Returning `false` stops the change.
- Each returns a function that removes it.

## Events

All events fire on `window`. The data is in `event.detail`.

| Event | detail | When |
| --- | --- | --- |
| `section-store:cart:ready` | `{ cart }` | The first cart has loaded |
| `section-store:cart:updated` | `{ cart, source }` | The cart changed. `source` is `"internal"` or `"external"`. |
| `section-store:cart:item-added` | `{ cart, lines }` | Lines appeared or grew |
| `section-store:cart:item-removed` | `{ cart, lines }` | Lines disappeared or shrank |
| `section-store:cart:opened` | `{ cart }` | The drawer opened |
| `section-store:cart:closed` | `{ cart }` | The drawer closed |
| `section-store:cart:discount-applied` | `{ cart, codes }` | New discount codes were applied |
| `section-store:cart:checkout-clicked` | `{ cart, checkoutUrl }`, plus `wallet` for express buttons | The shopper clicked checkout |
| `section-store:cart:error` | `{ error }` | A cart action failed. Its Promise rejects with the same message. |

## Utilities

| Member | Returns | What it does |
| --- | --- | --- |
| `formatMoney(cents)` | string | Formats an amount with the store's money format |
| `version` | string | The API version |
| `help()` | void | Prints the reference in the console |

## Good to know

- The `cart` object is Shopify's own cart JSON. Prices are in cents.
- The drawer takes over your theme's add-to-cart forms and cart links. It also watches cart calls from other scripts. Most themes and apps stay in sync with no code.
- Failed actions reject with Shopify's message when there is one.

## Check the drawer from the console

```js
typeof SectionStoreCart            // "object" means the drawer script loaded
SectionStoreCart.version           // "1"
SectionStoreCart.getCart()         // what the drawer has in the cart
SectionStoreCart.isOpen()

// Log every cart event
["ready","updated","item-added","item-removed","opened","closed","discount-applied","checkout-clicked","error"]
  .forEach(n => window.addEventListener("section-store:cart:" + n, e => console.log(n, e.detail)));
```

If `typeof SectionStoreCart` returns `"undefined"`, the drawer didn't load on that page. Check that your store has Plus, that the cart is **Active** and that the app embed is on in the theme you are viewing.

## Related

- [Add custom HTML to the cart drawer](https://section-store.orka.help/a/123-add-custom-html-to-the-cart-drawer)
- [Choose when the cart drawer opens](https://section-store.orka.help/a/choose-when-the-cart-drawer-opens)
- [Why ShipStation shows __section_store_cart_managed as a customer note](https://section-store.orka.help/a/116-why-shipstation-shows-sectionstorecartmanaged-as-a-customer-note)

*Also searched as:* cart drawer api, sectionstorecart, section store cart api, javascript api, js api, public api, cart drawer javascript, cart drawer events, cart events, cart updated event, section-store:cart, open cart drawer with code, open drawer programmatically, close cart drawer, trigger cart drawer, add to cart with javascript, addItem, add item api, update line quantity, remove line, clear cart, apply discount code with code, discount code api, set cart note, cart attributes, setAttributes, onBeforeCheckout, block checkout, prevent checkout, terms checkbox checkout, onBeforeAddToCart, hooks, cancel action, listen for cart changes, cart change listener, subscribe to cart, integrate with another app, developer, help(), console, debug cart drawer, formatMoney, item_count, checkoutUrl, window.SectionStoreCart, registerLineRules, onBeforeUpdateLines, onBeforeOpen, lock cart line
