A customer adds a limited-edition product to their cart. Your store is supposed to allow one per order, but the shopper changes the quantity to five.
Or a promotional bundle contains carefully selected quantities, and an editable cart input lets customers change the combination.
Hiding the quantity selector can simplify these experiences. But it does not, by itself, enforce the underlying rule.
The reliable solution has two layers: a storefront interface that communicates the restriction and a supported validation mechanism that prevents an invalid purchase.
This guide explains when theme code is sufficient, when native quantity settings can help, and when you need checkout validation.
- Define the quantity rule precisely
“Lock the quantity” can mean several different things:
Maximum one unit of a specific variant per order
Maximum one unit across every variant of a product
Exactly one promotional bundle when present
Products sold only in multiples of six
Maximum one purchase per customer across multiple orders
These are different requirements.
A per-variant maximum of one could still allow a customer to buy one small, one medium, and one large version of the same product.
Likewise, a per-order limit does not stop someone from placing another order.
Write the rule in plain language before implementing it:
Customers may buy at most one unit across all variants of this limited-edition product in a single order.
That statement tells the developer what to aggregate and where the restriction applies.
Also decide whether removal is allowed. “Quantity cannot be increased” should not accidentally become “the customer cannot remove this item.”
- Understand why hiding the input is not enforcement
The visible quantity field is only one way to change a cart.
Other paths can include repeated add-to-cart actions, a cart drawer, quick-add components, and requests made independently of the visible controls.
For that reason:
Hidden quantity selector
≠ Enforced quantity limit
CSS, a read-only input, and a JavaScript event handler all operate in the customer’s browser. They can improve the normal shopping experience, but they should not be treated as a security boundary.
Use presentation-only changes when the goal is to reduce accidental edits.
If the rule protects scarce inventory, bundle pricing, or promotional eligibility, add an enforcement layer.
- Check the native add-to-cart limit first
Shopify provides an Add-to-cart limit setting for a store-wide maximum quantity per variant.
It can be useful when the same ceiling should apply broadly. However, it is not a product-specific rules engine.
For example:
Store-wide maximum: 2
Blue variant: Up to 2
Black variant: Up to 2
The maximum applies independently to each variant, not to the combined product or whole cart.
Shopify also documents exceptions, including POS carts, draft orders, certain B2B scenarios, products without inventory tracking, and products configured to continue selling when out of stock.
Do not use this setting as proof that a product-level or customer-lifetime limit has been implemented.
For wholesale quantity increments or variant-specific minimums and maximums, Shopify B2B quantity rules are a separate option where that setup is available. Those rules address a different use case from simply hiding a retail cart input.
- Scope the theme change to the intended products
Avoid globally removing every quantity selector unless that is genuinely the desired experience.
A better pattern is to mark the affected products explicitly.
For example, define a Boolean product metafield:
Namespace and key:
custom.lock_cart_quantity
Type:
True or false
This is an illustrative custom definition, not a built-in Shopify setting.
Inside the theme’s existing cart-item loop, use that value to choose between a static quantity display and the normal controls:
{% assign lock_quantity = item.product.metafields.custom.lock_cart_quantity.value %}
{% if lock_quantity %}
<p class="cart-item__fixed-quantity">
Quantity: {{ item.quantity }}
</p>
<p class="cart-item__quantity-note">
Limited to one per order.
</p>
{% else %}
{% comment %}
Keep the theme's existing quantity controls here.
{% endcomment %}
{% endif %}
This example assumes the cart-line variable is named item. Themes can use different structures.
The snippet controls presentation only. It does not change the quantity or enforce the displayed limit.
Keep the removal action available unless a separate, well-defined bundle interaction requires a different approach.
- Preserve the theme’s existing cart behavior
Do not paste a generic replacement over an entire cart item.
Themes often attach behavior to specific elements, attributes, and form inputs. Quantity updates may also trigger subtotal changes, cart badges, discount displays, and accessibility announcements.
Before changing the markup, identify how the theme submits and updates cart quantities.
A hidden input can preserve a value in some form implementations, but it is not universally required and is not validation. A disabled input may not be submitted by the browser.
The correct implementation depends on the existing form and JavaScript.
Also render the actual cart quantity. Do not display a hard-coded “1” when the cart contains more than one unit. That hides the invalid state instead of resolving it.
- Cover every storefront entry point
A cart-page change does not automatically affect the cart drawer.
Review the full purchase journey:
Product-page quantity controls
Collection quick-add
Featured-product sections
Cart drawer
Full cart page
Recommendation widgets
Sticky add-to-cart components
Accelerated checkout paths
If the product page still allows a quantity of five, hiding the cart input creates a confusing experience: the shopper can create the cart but cannot easily correct it afterward.
Keep the interface consistent with the rule.
For example, a limited item can show a fixed purchase quantity and clear explanatory text before the add-to-cart action.
Even then, account for repeated additions. Clicking “Add to cart” twice must not become an unnoticed route around the intended maximum.
- Enforce the rule through supported validation
For product-specific restrictions that must prevent checkout, use a solution that supports cart and checkout validation.
Shopify documents validation apps that can enforce rules such as product purchase limits at checkout.
Confirm the actual mechanism and coverage. An app that only disables a theme’s checkout button is not equivalent to a checkout validation rule.
Ask the provider:
Does this rule prevent an invalid quantity at checkout, or does it only hide controls and block buttons in the storefront?
Also confirm support for the purchase paths your store offers and test them.
Plan and app distribution matter. Shopify’s documentation lists public apps built with Shopify Functions as available on Basic and higher, while custom apps containing Shopify Functions require Plus. That does not establish that every app or every validation feature works on every store.
After configuration, confirm that the rule is activated. Review its behavior if the validation encounters an error, and test that choice deliberately.
- Aggregate quantities across matching lines
A reliable maximum should not check each cart line in isolation.
The same product or variant can appear in multiple lines, depending on properties and other cart characteristics.
For a maximum of one across a product’s variants, the conceptual logic is:
function findProductLimitViolations(lines, restrictedProductIds) {
const quantities = new Map();
for (const line of lines) {
if (!restrictedProductIds.has(line.productId)) continue;
const current = quantities.get(line.productId) ?? 0;
quantities.set(line.productId, current + line.quantity);
}
return [...quantities.entries()]
.filter(([, quantity]) => quantity > 1)
.map(([productId, quantity]) => ({
productId,
quantity,
message: "Only one unit of this product is allowed per order."
}));
}
This is illustrative business logic using application-defined data. It is not a deployable Shopify Function.
A production implementation must use the supported validation input and output schemas and retrieve the required product identifiers or configuration.
The aggregation key matters:
Variant limit:
Group by variant identifier
Product-wide limit:
Group by product identifier
Promotion-group limit:
Group by a trusted promotion identifier
Do not trust a browser-supplied property as the sole authority for whether an item is restricted.
- Treat promotional bundles as a separate problem
A bundle restriction may need to preserve component relationships, not just a maximum quantity.
For example:
One promotional set:
1 jacket
2 shirts
1 accessory
Hiding quantity controls does not establish that the cart contains a valid set. A shopper might remove the jacket while retaining discounted shirts.
First decide whether the bundle is a single purchasable offering or a group of independent lines.
Then define what should happen when it changes. Possible behaviors include updating the whole set, removing the entire set, or rejecting an invalid composition.
Use the bundle implementation’s supported behavior rather than layering generic quantity-locking code over it.
Promotion pricing also needs its own protection. A hidden input should never be the only thing preserving eligibility for a special price.
- Give customers a way to recover
A validation error should explain both the problem and the next action.
Prefer:
Only one unit of this limited-edition product is allowed per order. Remove the extra unit to continue.
Avoid:
Invalid cart.
If you remove quantity controls, provide a correction mechanism for carts that already exceed the limit. Otherwise, you can create a checkout blocker with no obvious way out.
A repair action should preserve unrelated items and customer selections, update the affected lines safely, and render the confirmed result.
Do not silently delete paid products or change unrelated quantities while correcting the restricted item.
- Do not confuse per-order limits with customer limits
A cart rule can restrict the current order. It does not automatically enforce “one per customer forever.”
Cross-order limits require an identity policy, purchase-history handling, and decisions about cancellations, refunds, guest checkout, and simultaneous purchases.
An email address alone is not a robust anti-abuse strategy.
Describe the rule honestly. If the implementation enforces one per order, say “one per order,” not “one per customer.”
For highly limited releases, inventory controls and abuse prevention are separate layers that may also be necessary.
- Test bypasses and recovery before launch
Use a test matrix that includes more than editing the visible input.
- Add the restricted item repeatedly.
- Add different variants of the same restricted product.
- Test matching items split across multiple lines.
- Open both the drawer and full cart page.
- Test with JavaScript unavailable where practical.
- Verify that direct cart changes cannot produce a completed invalid purchase.
- Test accelerated checkout paths.
- Start with an already-invalid cart.
- Remove the restricted item completely.
- Confirm unrestricted products remain editable.
- Test bundle-component removal and invalid combinations.
- Confirm that customer-facing errors provide a usable correction path.
Repeat the tests after theme updates or changes to cart-related apps.
The recommended workflow
Use the theme to explain the restriction and supported validation to enforce it.
Define the exact rule
→ Check applicable native limits
→ Scope the affected products
→ Simplify storefront quantity controls
→ Activate the enforcement layer
→ Provide an invalid-cart recovery path
→ Test alternate purchase paths
For a visual cleanup, a conditional Liquid change may be enough. For limited-edition products or promotional bundles, it is only the interface layer. The purchase rule must still hold when the customer never interacts with that input.