Hide Cash on Delivery above a cart total

A Shopify payment customization Function that hides Cash on Delivery when the cart total is above a limit you set, with tested JavaScript.

Function API
Payment Customization
Target
cart.payment-methods.transform.run
Plan
Any plan in a public app; Shopify Plus in a custom app
App scope
write_payment_customizations
API version
2026-10
Last checked

In short

This payment customization Function hides Cash on Delivery at checkout when the cart total is above a limit, 5,000 by default. The limit and the payment method names are read from a JSON metafield, so you can change them without a deploy. It uses the cart.payment-methods.transform.run target of the Payment Customization API, version 2026-10.

How to use it

  1. Create an app with the Shopify CLI (shopify app init), then add a Function extension: shopify app generate extension, and pick Payment customization with JavaScript.
  2. Replace the generated shopify.extension.toml and the two files in src/ with the files below.
  3. Run the tests: shopify app function run --input tests/above-limit.input.json (and the other fixtures).
  4. Deploy with shopify app deploy and install the app on the store.
  5. Create the customization with the paymentCustomizationCreate mutation, and set the function-configuration metafield if you want a different limit or method name.

Code

shopify.extension.toml
api_version = "2026-10"

[[extensions]]
name = "Hide Cash on Delivery above a cart total"
handle = "hide-cod-above-total"
type = "function"

  [[extensions.targeting]]
  target = "cart.payment-methods.transform.run"
  input_query = "src/cart_payment_methods_transform_run.graphql"
  export = "cart-payment-methods-transform-run"

  [extensions.build]
  command = ""
  path = "dist/function.wasm"
src/cart_payment_methods_transform_run.graphql
query CartPaymentMethodsTransformRunInput {
  cart {
    cost {
      totalAmount {
        amount
      }
    }
  }
  paymentMethods {
    id
    name
  }
  paymentCustomization {
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
src/cart_payment_methods_transform_run.js
// @ts-check

/**
 * @typedef {import("../generated/api").CartPaymentMethodsTransformRunInput} CartPaymentMethodsTransformRunInput
 * @typedef {import("../generated/api").CartPaymentMethodsTransformRunResult} CartPaymentMethodsTransformRunResult
 */

/**
 * Settings stored as JSON in the customization's metafield, so the limit can
 * change without a deploy. Used when the metafield is missing.
 */
const DEFAULT_CONFIG = {
  // Cart total (in the checkout currency) above which the methods are hidden.
  maxAmount: 5000,
  // Matched case-insensitively against the start of the payment method name.
  methodNames: ["Cash on Delivery", "Kapıda Ödeme"],
};

/**
 * Lowercase for matching, with Turkish dotless/dotted i folded to "i", so
 * "KAPIDA ÖDEME" and "Kapıda Ödeme" match the same configured name.
 * @param {string} text
 */
const fold = (text) => text.toLowerCase().replace(/ı/g, "i").replace(/\u0307/g, "");

/** @type {CartPaymentMethodsTransformRunResult} */
const NO_CHANGES = { operations: [] };

/**
 * @param {CartPaymentMethodsTransformRunInput} input
 * @returns {CartPaymentMethodsTransformRunResult}
 */
export function cartPaymentMethodsTransformRun(input) {
  const config = { ...DEFAULT_CONFIG, ...input.paymentCustomization?.metafield?.jsonValue };
  const total = Number(input.cart.cost.totalAmount.amount);
  if (!(total > config.maxAmount)) return NO_CHANGES;

  const names = config.methodNames.map(fold);
  const operations = input.paymentMethods
    .filter((method) => names.some((name) => fold(method.name).startsWith(name)))
    .map((method) => ({ paymentMethodHide: { paymentMethodId: method.id } }));

  return { operations };
}
Test input and expected output
tests/above-limit.input.json
{
  "cart": { "cost": { "totalAmount": { "amount": "6250.0" } } },
  "paymentMethods": [
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Credit card" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "Cash on Delivery (COD)" }
  ],
  "paymentCustomization": { "metafield": null }
}
tests/above-limit.output.json
{
  "operations": [
    { "paymentMethodHide": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/2" } }
  ]
}
tests/below-limit.input.json
{
  "cart": { "cost": { "totalAmount": { "amount": "4999.99" } } },
  "paymentMethods": [
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Credit card" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "Cash on Delivery (COD)" }
  ],
  "paymentCustomization": { "metafield": null }
}
tests/below-limit.output.json
{ "operations": [] }
tests/configured-limit.input.json
{
  "cart": { "cost": { "totalAmount": { "amount": "1500.0" } } },
  "paymentMethods": [
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Kredi kartı" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "Kapıda Ödeme" }
  ],
  "paymentCustomization": {
    "metafield": { "jsonValue": { "maxAmount": 1000, "methodNames": ["Kapıda Ödeme"] } }
  }
}
tests/configured-limit.output.json
{
  "operations": [
    { "paymentMethodHide": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/2" } }
  ]
}
tests/uppercase-turkish-name.input.json
{
  "cart": {
    "cost": {
      "totalAmount": {
        "amount": "6250.0"
      }
    }
  },
  "paymentMethods": [
    {
      "id": "gid://shopify/PaymentCustomizationPaymentMethod/1",
      "name": "Credit card"
    },
    {
      "id": "gid://shopify/PaymentCustomizationPaymentMethod/2",
      "name": "KAPIDA ÖDEME"
    }
  ],
  "paymentCustomization": {
    "metafield": null
  }
}
tests/uppercase-turkish-name.output.json
{
  "operations": [
    { "paymentMethodHide": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/2" } }
  ]
}

Written by Lintel. MIT license: free to use in your own store and in client work.

Limits and edge cases

  • The cart total is in the currency the customer pays in. With several currencies, set the limit for the lowest-value currency you sell in.
  • Methods are matched by the start of their name, as the customer sees it at checkout. Check the exact name of your Cash on Delivery method under Settings › Payments.
  • Hiding a method only for some placements (for example accelerated checkout) is Shopify Plus only; this example hides it everywhere.
  • A store can have up to 25 payment customizations.

Questions

Can I hide Cash on Delivery without an app?
Not by cart total. Shopify’s payment settings have no amount rule, so a payment customization Function is the supported way. Apps in the Shopify App Store package the same kind of Function.
Does this work on Basic or Shopify plans?
Yes, when the Function is part of a public app. Functions in a custom app only run on Shopify Plus stores.
How do I change the limit later?
Write {"maxAmount": 3000} to the customization’s $app:function-configuration metafield with metafieldsSet. The Function reads it on the next checkout; no redeploy needed.
Can I hide it for certain products instead?
Yes. Add cart.lines with each line’s product tags to the input query and hide the method when a tagged product is in the cart. The operation is the same paymentMethodHide.
  • Written for Function API version 2026-10 and checked against Shopify’s reference on the date shown. Shopify releases a new version every quarter.
  • Custom apps that contain Functions only run on Shopify Plus stores; a public app with the same Function runs on any plan unless the page says otherwise.
  • Every example ships with test fixtures, and we run them before publishing. Run them again after you change the code: shopify app function run.
  • MIT license. Use the code in your own store or in client work.

Need this built, tested and maintained for your store? See Shopify Functions development.

Have something to build? Let’s talk it through.

Taking a limited number of projects at a time. Every brief is read by an engineer, not a salesperson.

Gencer KarakayaShopify Engineer

An engineer reads your brief, and we reply by email.