Shopify Scripts Stopped Executing on June 30: Find Your Silently Broken Discounts, Shipping, and Payment Rules

By Milan Dhameliya · · 8 min read

Shopify Scripts stopped running on June 30, 2026 with no error message. Here's how to audit what broke, migrate to Shopify Functions, and rebuild before the Script Editor itself disappears on July 30.

If your store ever used the Script Editor for custom discounts, shipping rules, or payment method gating, there is a good chance part of your checkout has been running on Shopify's defaults since June 30, 2026 — and nobody told you. Shopify Scripts stopped executing on that date. There is no banner in checkout, no failed-order alert, and no email to the customer. The script simply stops running, the cart falls back to standard pricing and standard delivery and payment options, and the store keeps taking orders as if nothing changed.

The window to do anything about it is closing fast. Editing and publishing Scripts was already frozen on April 15, 2026, and the Script Editor itself — the only place your old script code still lives — is scheduled to go away on July 30, 2026. If you have not exported your existing Script logic yet, you have days, not months, before the reference copy disappears along with the feature.

Why this fails silently instead of loudly

Scripts ran inside Shopify's old Ruby-based checkout runtime and could rewrite the cart directly: apply a discount, hide a shipping rate, hide a payment method. When that runtime stopped executing Script code, checkout did not throw an error — it just stopped applying the customization and rendered the cart with whatever the storefront and native discount engine would produce on their own. A tiered wholesale discount silently disappears. A shipping rule that hid "Local pickup" for out-of-zone postcodes silently reappears for everyone. A payment method gate that blocked cash-on-delivery above a certain order value silently stops blocking it.

None of this trips a Shopify error, an app error, or a payment failure. The order still completes. The only way to notice is to go looking for it.

Problem breakdown: what is actually at risk

  1. Discount Scripts — tiered, bulk, B2B/wholesale, or customer-tag-based pricing that lived outside the standard discount code UI.
  2. Shipping Scripts — hiding or reordering delivery options by cart weight, destination, tag, or line item.
  3. Payment customization Scripts — hiding a payment method for certain order values, customer tags, or shipping countries, often used to block COD fraud or restrict a gateway to specific regions.
  4. B2B and wholesale logic is the highest-risk category: it frequently encodes credit limits, purchase-order validation, or buyer eligibility rules that are legally or financially meaningful, not just cosmetic pricing.
  5. The reference copy is disappearing. Because Scripts stopped executing, you cannot verify old behavior by testing checkout anymore — the Script Editor's stored code, until July 30, 2026, is the only remaining record of what the logic was supposed to do.

Audit workflow: do this before the Script Editor closes

  1. Go to Shopify admin's Script Editor while it still loads and export or copy every script's source, name, and the trigger it was attached to (line item, shipping rate, or payment method).
  2. Sort scripts into three buckets: discount, shipping, payment. Note which ones affect price, which affect delivery method visibility, and which affect payment method visibility or eligibility.
  3. For each script, run a real test checkout with a cart and customer profile that should have triggered it, and record what actually happens today. Compare it against what the script's code says should happen.
  4. Flag any mismatch as a live revenue or compliance issue, not a backlog item — a payment gate or credit-limit rule that has quietly stopped enforcing itself is the most expensive kind of bug because it does not generate a support ticket.
  5. Rank by business impact: B2B/wholesale pricing and payment gating first, promotional discounts second, cosmetic shipping-label renaming last.
# Repo / theme audit for anything that assumed Script Editor behavior
rg -i 'script_discount|shipping.*script|payment.*script|line_item.change_line_price|Input\.cart' .

Two migration paths: Shopify Functions or a function-based app

Shopify Functions are the direct replacement, but they are not a line-for-line port of Ruby Script code. A Function is a small compiled module (JavaScript or Rust) that receives a GraphQL input query describing the cart, customer, and discount context, and returns a set of operations for Shopify to apply — it does not mutate the cart object directly the way a Script did.

When to write a custom Function

When to use a function-based app instead

Scaffolding a replacement Function

For custom logic, Shopify CLI generates the extension scaffold. A discount function targeting cart line items looks roughly like this:

shopify app generate extension --template=product_discounts --name=wholesale-tier-discount

That generates a config file, an input query, and the function body:

# shopify.extension.toml
api_version = "2026-01"

[[extensions]]
name = "t:name"
handle = "wholesale-tier-discount"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "npm run build"
path = "dist/index.js"
# src/cart_lines_discounts_generate_run.graphql
query Input {
  cart {
    lines {
      id
      quantity
      cost { subtotalAmount { amount } }
      merchandise {
        ... on ProductVariant {
          product { hasTags(tags: ["wholesale"]) { hasTag } }
        }
      }
    }
    buyerIdentity { customer { hasTags(tags: ["tier-2"]) { hasTag } } }
  }
  discount { discountClasses }
}
// src/cart_lines_discounts_generate_run.js
export function cartLinesDiscountsGenerateRun(input) {
  const isTier2 = input.cart.buyerIdentity?.customer?.hasTags?.some(
    (t) => t.hasTag
  );
  if (!isTier2) {
    return { operations: [] };
  }

  const candidates = input.cart.lines
    .filter((line) =>
      line.merchandise.product?.hasTags?.some((t) => t.hasTag)
    )
    .map((line) => ({
      targets: [{ cartLine: { id: line.id } }],
      value: { percentage: { value: "10" } }
    }));

  if (candidates.length === 0) return { operations: [] };

  return {
    operations: [
      { productDiscountsAdd: { candidates, selectionStrategy: "ALL" } }
    ]
  };
}

Shipping rules use the same shape against the Delivery Customization API (hiding, renaming, or reordering delivery methods); payment gating uses the Payment Customization API. The JavaScript runtime here (compiled through Javy to WebAssembly) has no event loop — no async/await, no fetch, no setTimeout. Anything that needs an external call has to happen before checkout, not inside the Function.

Roll out behind a test-customer tag first

Do not point a new Function at every customer on day one. Tag a handful of internal or trusted accounts (for example, TESTER), scope the Function's logic to only apply when that tag is present, and run real checkouts against every discount tier, shipping zone, and payment method the old script touched before removing the tag condition and going live for everyone.

Technical checklist

When to bring in a Shopify developer

If your store had more than a couple of Scripts, or any of them touched B2B pricing, credit limits, or payment eligibility, treat this as a checkout-integrity project, not a quick admin fix. Code Kaarigari can audit your old Script logic, rebuild it as Shopify Functions, and verify it against real checkout scenarios before your discounts, shipping rules, or payment gates go live again. Start with our Shopify development and checkout services, read more on checkout customization and checkout extensibility or what else changed on the Thank you and checkout pages this year, or contact Code Kaarigari for a Scripts-to-Functions audit.

Sources reviewed