Cart & checkout

AJAX cart setup

Turn on AJAX cart mode, point the app at your theme's cart selectors, and run a custom add-to-cart callback.

When a customer adds, removes, or changes the quantity of something in their cart, you usually want the cart and your upsell widgets to update right away — without the page reloading. That is exactly what AJAX cart mode does. This guide is the deep dive on the Cart page section of Settings: what each field means, how to find the right selectors for your theme, how the add-to-cart callback works, and how to fix the most common setup problems.

What AJAX cart mode does

AJAX cart mode lets cart updates happen without a full page reload. When it is on, the app intercepts cart changes and refreshes the cart contents — and any upsell widgets tied to the cart — in place. This keeps the cart subtotal, line items, progress bars, and widgets in sync after every add, remove, or quantity change, so a customer never sees a stale total or a widget that hasn't caught up.

The setting that controls this is Enable AJAX (enableAjaxCart). It is off by default. With it off, the app relies on a normal page reload to show updated cart state, which is the safe choice for themes that already handle their own cart updates (more on that below).

AJAX cart mode is about the app keeping itself in sync with your theme's cart. It does not replace your theme's cart — for that, see Llama Cart further down this page.

The two required selectors

When Enable AJAX is on, the app needs to know where on the page your theme draws the cart, so it can update those regions in place. You provide that with two CSS selectors. Both are required whenever AJAX is enabled.

SettingFieldDefaultWhat it points to
Cart items Container SelectoritemsContainerSelector.cart-itemsThe element that wraps your cart line items (the list of products in the cart).
Cart Footer SelectorcartFooterSelector.cart__footerThe element that wraps your cart footer — subtotal, taxes/shipping note, and the checkout button.

These selectors tell the app which parts of the rendered cart page to re-render when something changes. If they point at the wrong elements — or at nothing — the app can't update the cart in place, and you'll see the symptoms described in Edge and complex cases.

The defaults .cart-items and .cart__footer match Shopify's Dawn theme. They will not necessarily match your theme. Always verify the selectors against your own cart template before relying on them.

How to find the right selectors for your theme

Every theme structures its cart page a little differently, so the safest way to set these is to inspect your live cart template.

Open your cart page

Add a product to your cart and go to /cart on your storefront (or open the cart page directly in your browser).

Inspect the cart items wrapper

Right-click the list of cart line items and choose Inspect. Find the element that wraps all the line items (not a single row). Note its class or id, and write it as a CSS selector — for example .cart-items, #main-cart-items, or .cart__items.

Right-click near the subtotal / checkout button and choose Inspect. Find the wrapper around the subtotal and checkout button, and note its selector — for example .cart__footer, .cart-footer, or .totals.

Enter both selectors and save

Paste the items-container selector into Cart items Container Selector and the footer selector into Cart Footer Selector, then Save.

Common selectors by theme family

These are good starting points, but always confirm against your own theme since merchants and developers often rename classes:

ThemeLikely items containerLikely footer
Dawn (and the app defaults).cart-items.cart__footer
Horizon and other Online Store 2.0 themesa cart-items-style wrapper or #main-cart-itemsa cart__footer-style wrapper
Custom / heavily modified themesinspect the template — selectors are often renamedinspect the template

For an Online Store 2.0 theme, the cart markup usually lives in sections/main-cart-items.liquid and sections/main-cart-footer.liquid (or similar). If you have theme code access, opening those files is the fastest way to confirm the exact wrapper class. For custom themes, there is no shortcut — inspect the rendered page and use whatever wrapper your developer used.

The add-to-cart callback

Sometimes you want your own JavaScript to run every time a product is added to the cart — to fire an analytics event, open a cart drawer, or show a toast. The app supports this with two settings:

SettingFieldDefaultWhat it does
Enable Callback FunctionuseAddToCartCallbackfalse (off)Turns the custom callback on. While off, your callback code is ignored.
Callback JavaScript codeonAddToCartCallbackemptyThe JavaScript that runs whenever a product is added to the cart.

How the callback behaves:

  • No <script> tag. Paste plain JavaScript only — do not wrap it in <script>...</script>. The app injects and runs it for you.
  • Runs on every add-to-cart. Your code executes each time a product is added to the cart through the app's flow.
  • You get an item variable. Inside your callback, a variable named item holds the data for the product that was just added. Use it to read the product's details for analytics or messaging.

Example callbacks

Fire a custom analytics event with the added product:

// `item` is the product that was just added to the cart
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  event: 'app_add_to_cart',
  product: item,
});

Show a quick confirmation toast:

const toast = document.createElement('div');
toast.className = 'app-toast';
toast.textContent = 'Added to cart';
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 2500);

Open the theme's cart drawer after an add (selector depends on your theme):

// Many Online Store 2.0 themes expose the drawer as a custom element
document.querySelector('cart-drawer')?.classList.add('active');
document.querySelector('cart-drawer')?.removeAttribute('hidden');

Callback code is your responsibility — the app does not sanitize or validate it. A callback that throws an error can interrupt the add-to-cart flow and stop products from being added. Always test your callback on a development or unpublished theme first, and keep it defensive (for example, use optional chaining like ?. and guard against missing elements).

Relationship to Llama Cart

The selectors and AJAX setting apply to your theme's cart page. They matter most when customers use the standard theme cart.

Llama Cart is the app's own AJAX cart drawer. When you enable Llama Cart, it replaces the theme cart with the app's drawer, and the drawer handles its own rendering and updates. In that setup, the theme cart selectors are about your theme's /cart page rather than the Llama Cart drawer itself.

Your setupWhat matters
Theme cart (Llama Cart off)Enable AJAX, Cart items Container Selector, and Cart Footer Selector point the app at your theme's cart so it can update line items, the footer, and widgets in place.
Llama Cart drawer (Llama Cart on)The app's drawer replaces the theme cart and manages its own rendering. The theme cart selectors describe the underlying theme /cart page rather than the drawer.

The Enable Llama Cart toggle lives in the app's shop settings, separate from the Cart page section. To customize the drawer itself, see Widgets and Llama Cart.

Price formatting in the AJAX-updated cart

When the app re-renders the cart, prices are formatted according to your Price Decimal Scale setting (priceDecimalScale), found in the Global section of Settings. This is worth knowing here because it controls how every price looks in the cart the AJAX flow updates.

OptionField valueEffect
Enforce 2 Decimal PlacesFIXED_TWO (default)Always shows two digits — for example, 2 renders as 2.00.
Trim Unnecessary ZerosDYNAMICRemoves trailing zeros — for example, 2.00 renders as 2.

This value also syncs to the global app metafield, so storefront widgets read it directly without an extra API call — keeping the AJAX-updated cart and your widgets formatting prices the same way. Full details are in Cart & checkout settings.

Edge and complex cases

Recipe: enable AJAX, set selectors, verify, add a drawer callback

Enable AJAX

In Settings → Cart page, turn on Enable AJAX.

Set both selectors

Inspect your cart page and enter the wrapper selectors into Cart items Container Selector and Cart Footer Selector. On Dawn the defaults .cart-items and .cart__footer usually work; on other themes use what you found by inspecting.

Save

Click Save in the sticky save bar. Unsaved changes do not apply to your storefront.

Verify with a test add-to-cart

On your storefront, add a product to the cart, then change its quantity and remove it. Confirm the line items, subtotal, and any upsell widgets update without a full page reload. If they don't, revisit your selectors in Edge and complex cases.

Add a callback that opens the theme drawer

Turn on Enable Callback Function, then paste a small script into Callback JavaScript code (no <script> tag) that opens your theme's drawer — for example:

document.querySelector('cart-drawer')?.classList.add('active');

Save, then add a product and confirm the drawer opens. Adjust the selector to match your theme's drawer element.

Troubleshooting

ProblemLikely causeFix
Cart doesn't update without reloadWrong/missing selectors, or AJAX is offVerify Enable AJAX is on; re-inspect and correct both selectors.
Widgets show stale cart dataItems container selector doesn't wrap all line itemsPoint Cart items Container Selector at the full line-item wrapper.
Subtotal/footer doesn't refreshFooter selector is wrongPoint Cart Footer Selector at the subtotal/checkout wrapper.
Add-to-cart stopped working after editing the callbackCallback throws an errorTurn off Enable Callback Function, confirm add-to-cart works, fix the code, re-enable.
Selectors worked before, now they don'tTheme update/switch renamed the markupRe-inspect the cart page and update the selectors.

On this page