Skip to content

Shopify Dude Fix

Shopify Checkout Validation Not Blocking Orders? Check the Merchant Toggle and Move Rules to Functions

A checkout UI extension can display a warning yet let orders through. Diagnose merchant blocking permissions, the 2026 buyer-journey deprecation, and server-side Validation Functions.

Type: Fix / Developer Guide · Stage: Optimize · Topic: Checkout / Validation Functions

On this page

Quick answer

If your checkout UI extension displays an error but the customer can still pay, do not assume the interception code is broken. As of January 26, 2026, checkout UI extensions that support blocking default to non-blocking until the merchant explicitly enables Allow app to block checkout in the checkout and accounts editor. Even when that permission is granted, Shopify deprecated the useBuyerJourneyIntercept hook and block_progress capability starting with API version 2026-07. For rules that must stop an order—quantity caps, restricted billing countries, B2B minimums, required business fields—build a Cart and Checkout Validation Function instead.

There are two separate questions: Did the UI extension get permission to block? and Is UI interception the right enforcement mechanism? Answer both before changing code.

What changed in 2026

Older tutorials demonstrate useBuyerJourneyIntercept, a block_progress declaration in shopify.extension.toml, and a return value with behavior: 'block'. That pattern was valid for the API versions those tutorials targeted. It is no longer the preferred architecture for business rules that must be enforced across checkout surfaces.

On January 26, 2026, Shopify changed the default behavior: a merchant must actively allow a checkout UI extension to block checkout. On July 2, 2026, Shopify announced that the intercept hook and its blocking capability are deprecated as of API 2026-07. Deprecation does not mean every existing extension immediately stopped running. It means the old approach remains available in supported versions for now but is scheduled for removal in a future version.

Diagnose the current extension before rebuilding it

  1. Confirm where the rule lives. A disabled cart button in theme JavaScript, a checkout UI extension, and a Validation Function are different mechanisms. If a shopper can reach checkout through Shop Pay or a direct link, a theme-only gate was never authoritative.
  2. Inspect the extension version and configuration. Find the extension’s shopify.extension.toml, its target, and any block_progress capability. A deployment that builds successfully does not prove the merchant granted that capability.
  3. Open the checkout and accounts editor. Select the app block and inspect whether the merchant has enabled Allow app to block checkout. Check the actual live checkout configuration, not only a local preview.
  4. Look at the interception result. In older APIs, the intercept callback receives canBlockProgress. If it is false, the extension can show an error but cannot stop progress. Treat that state as a permission outcome, not a JavaScript exception.
  5. Test the bypasses. A requirement that works in standard checkout but not in express wallets is not safely enforced. Test Shop Pay, PayPal, and the relevant storefront or custom-storefront flow.

Local preview trap: Shopify’s capability documentation notes that local development may automatically grant block_progress. A successful local test can therefore hide a missing merchant permission in production.

Use the correct enforcement layer

Requirement Recommended layer Reason
Show a warning or collect optional UI input Checkout UI extension Presentation belongs in the interface.
Prevent more than five units of a restricted item Cart and Checkout Validation Function Quantity must be checked against the actual cart on supported checkout surfaces.
Reject non-US billing countries for a warranty product Cart and Checkout Validation Function Billing restrictions must not depend on a visible UI block.
Require a B2B purchase-order value or enforce order minimums Cart and Checkout Validation Function The rule must be evaluated against buyer/cart context.
Reject a discount code with a specific reason Discount Function API Shopify recommends discount logic rather than buyer-journey interception.

Build a server-side Validation Function

In an app project using Shopify CLI, generate the current Function extension template:

shopify app generate extension --template cart_checkout_validation --name cart-checkout-validation

Request only the data your rule needs in the Function’s GraphQL input query. For a quantity cap, inspect cart lines and the relevant merchandise/product identifiers. For a billing-country restriction, query the billing address country code where the Function API exposes it. For a B2B minimum, query the appropriate company or buyer context rather than relying on customer tags alone.

The Function’s target is cart.validations.generate.run. When a rule fails, return a validationAdd operation containing one or more errors. A cart-level error uses the target $.cart; supported field-level targets include $.cart.billingAddress.countryCode. Use the schema generated for your selected API version rather than copying a historical Function output shape.

{
  "operations": [
    {
      "validationAdd": {
        "errors": [
          {
            "message": "This item can only be purchased in quantities of five or fewer.",
            "target": "$.cart"
          }
        ]
      }
    }
  ]
}

Illustrative Function output only: the condition that decides when to return the error belongs in your compiled Function code. It is not a complete extension and should not be pasted into a theme.

After deployment, open Settings → Checkout → Checkout rules → Add rule, select the deployed validation, and activate it. Shopify’s current tutorial includes an optional fail-open setting for runtime exceptions (Allow all customers to submit checkout); choose that deliberately based on the business requirement rather than leaving its implications untested.

Common misunderstanding

“My UI extension says the order is invalid, so checkout must be blocked.” Displaying a banner and preventing submission are separate outcomes. A banner can be visible while the buyer is still allowed to continue.

“Deprecated means it stopped working in July.” Shopify announced future removal, not an immediate shutdown of every deployed interceptor. The migration is urgent because it is the supported long-term design, not because every old app instantly fails.

“A disabled Add to cart button enforces a purchase limit.” It improves the interface but can be bypassed by other cart entry points, API requests, and accelerated checkout. Enforce the final limit server-side.

How to test this

  1. On a development store, create one qualifying cart that must be rejected and one nearly identical cart that must pass.
  2. For the legacy UI extension, test with the merchant blocking permission enabled and disabled; record whether canBlockProgress changes.
  3. Activate the Validation Function under checkout rules. Verify that the failing cart shows a specific error and cannot complete checkout.
  4. Test standard checkout, Shop Pay and any other supported accelerated checkout your store offers. Do not claim coverage for unsupported surfaces.
  5. Test a custom storefront cart mutation if applicable; inspect returned userErrors rather than assuming the mutation succeeded.
  6. Test null/missing billing addresses, multiple cart lines, changed quantities, subscription context, and an eligible cart.
  7. Review Function execution logs or replay a recorded execution before production release. Verify both the blocked and allowed paths after activation.

Sources and further reading

Documentation checked October 14, 2026.