Quick answer
If a product is limited to five units, setting max="5" on the product-page quantity input is not enough. A shopper can add three units, return to the product page, and add three more. To make the storefront behave correctly, read the current cart, total the matching quantities, and disable or adjust Add to cart when the remaining allowance reaches zero.
If five is a hard purchasing rule, not just a storefront convenience, enforce it server-side with an appropriate Shopify Cart and Checkout Validation Function as well. A theme button can be bypassed by direct requests, cart edits, or another sales surface.
On this page
Decide what “five” actually means
Before changing JavaScript, define the rule: five of the same variant, five across all variants of one product, or five across a group of products? Those produce different totals. Also decide whether the cap applies per cart, per order, or per customer over time. A cart validation alone does not implement a lifetime purchase limit.
Shopify can have multiple cart lines for the same variant when line-item properties, selling plans, or pricing characteristics differ. Checking only the first matching line is a common reason a limit appears to work until personalization or subscriptions enter the picture.
Use the Ajax cart as the storefront’s current quantity source
Shopify’s locale-aware Ajax API exposes the cart at window.Shopify.routes.root + 'cart.js'. For a variant-wide cap, sum every matching line:
async function remainingForVariant(variantId, limit = 5) {
const root = window.Shopify?.routes?.root || '/';
const response = await fetch(root + 'cart.js', {
credentials: 'same-origin',
cache: 'no-store'
});
if (!response.ok) throw new Error('Unable to read cart');
const cart = await response.json();
const inCart = cart.items
.filter(item => Number(item.variant_id) === Number(variantId))
.reduce((sum, item) => sum + item.quantity, 0);
return Math.max(0, limit - inCart);
}
For a product-wide cap, compare item.product_id instead, and sum every variant. If the limit comes from a metafield, render that value into the product form rather than scattering magic numbers through several theme files.
Update the button and quantity picker together
When the selected variant changes, or a cart drawer add/change/remove operation succeeds, recompute the remaining allowance. Set the quantity input’s maximum to the remaining amount and disable the relevant Add to cart controls when it is zero. Explain the disabled state with text such as “Maximum of 5 already in cart.”
const remaining = await remainingForVariant(selectedVariantId, 5);
quantityInput.max = String(Math.max(1, remaining));
quantityInput.disabled = remaining === 0;
addButton.disabled = remaining === 0;
addButton.textContent = remaining === 0
? 'Maximum already in cart'
: 'Add to cart';
This is an integration pattern, not a drop-in replacement for a theme’s product-form controller. A real implementation must also clamp the currently selected quantity, respect the theme’s loading state, avoid overwriting a sold-out label, and handle failed cart requests. In a theme with several Add to cart surfaces—product page, quick-add, sticky bar, upsell widget—update all of them from the same rule.
Protect against stale carts and double-clicks
Do not fetch the cart only once at page load. The cart can change in another tab, in a drawer, or through an app. Disable the submit control while an add request is pending, then refresh the cart state after success. If an add fails, show the error and restore the correct button state. Shopify’s Cart Ajax API may return inventory-related errors when the available quantity has already been reached; do not silently retry the same add.
When native quantity rules are the right tool
Shopify has catalog quantity rules for B2B with minimum, maximum, and increment values. Those are different from an arbitrary five-unit rule you add to a regular DTC product form. Check whether your store’s native catalog rules already cover the use case before creating custom logic.
For a checkout-enforced custom cap, a Cart and Checkout Validation Function can inspect cart lines and product metafields, total the relevant quantities, and return a validation error when the cap is exceeded. Shopify’s documentation includes a product-metafield quantity-limit example. If the same product can be split across lines, aggregate the lines before comparing to the limit.
Common misunderstanding
“The quantity picker says maximum five, so nobody can buy six.” The picker limits one interaction, not the customer’s cart total. Disabling Add to cart improves the interface, but it is not a server-side purchasing rule.
How to test this
- Start empty, add three units, revisit the page, and confirm only two remain available.
- Add the fifth unit; confirm product-page, quick-add, and sticky Add to cart controls all disable.
- Remove or reduce a unit in the drawer; confirm the controls become available again.
- Test two variants of one product to verify whether the rule is per variant or per product as intended.
- Test separate cart lines created by different line-item properties or selling plans.
- Test rapid double-clicks, slow network responses, multiple tabs, and a direct Ajax cart request.
- If a Validation Function enforces the rule, test normal checkout and accelerated checkout; confirm an over-limit cart cannot complete.

