# 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.

Page: https://lintelagency.com/resources/shopify-functions/hide-cash-on-delivery-above-cart-total

## 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.

## Facts

- **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:** 2 November 2026

## 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

```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

```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

```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

```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

```json
{
  "operations": [
    { "paymentMethodHide": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/2" } }
  ]
}
```

### tests/below-limit.input.json

```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

```json
{ "operations": [] }
```

### tests/configured-limit.input.json

```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

```json
{
  "operations": [
    { "paymentMethodHide": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/2" } }
  ]
}
```

### tests/uppercase-turkish-name.input.json

```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

```json
{
  "operations": [
    { "paymentMethodHide": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/2" } }
  ]
}
```

## 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.

## Shopify documentation

- [Payment Customization Function API](https://shopify.dev/docs/api/functions/latest/payment-customization)
- [Function limits and app types](https://shopify.dev/docs/api/functions)

## Related

- [Activate a delivery, payment or validation Function](https://lintelagency.com/resources/graphql/register-function-customization)
- [Shopify Scripts stopped running. Here is where each script’s logic goes now.](https://lintelagency.com/journal/shopify-scripts-to-functions)
- [Which Shopify Functions capabilities need Shopify Plus](https://lintelagency.com/journal/shopify-functions-plus-requirements)
- [Configuring Functions with metafields, so rules change without deploys](https://lintelagency.com/journal/configuring-functions-with-metafields)

License: MIT. Free to use in your own store and in client work.
