# Hide express shipping for heavy carts

> A Shopify delivery customization Function that hides express rates when a shipment weighs more than a limit, 30 kg by default. Tested JavaScript.

Page: https://lintelagency.com/resources/shopify-functions/hide-express-shipping-for-heavy-carts

## In short

This delivery customization Function adds up the product weight of each shipment and hides express options when it’s above a limit, 30 kg by default. The limit and the option names come from a JSON metafield. It uses the cart.delivery-options.transform.run target of the Delivery Customization API, version 2026-10, and works on any plan in a public app.

## Facts

- **Function API:** Delivery Customization
- **Target:** cart.delivery-options.transform.run
- **Plan:** Any plan in a public app; Shopify Plus in a custom app
- **App scope:** write_delivery_customizations
- **API version:** 2026-10
- **Last checked:** 2 November 2026

## How to use it

1. Create an app with the Shopify CLI, then add the extension: shopify app generate extension --template delivery_customization, with JavaScript.
2. Replace the generated shopify.extension.toml and the two files in src/ with the files below.
3. Run the fixtures with shopify app function run --input tests/heavy-cart-in-pounds.input.json.
4. Deploy with shopify app deploy and create the customization with deliveryCustomizationCreate.
5. Optionally set the $app:function-configuration metafield, for example {"maxWeightKg": 20, "optionTitles": ["Express", "Overnight"]}.

## Code

### shopify.extension.toml

```toml
api_version = "2026-10"

[[extensions]]
name = "Hide express shipping for heavy carts"
handle = "hide-express-heavy-carts"
type = "function"

  [[extensions.targeting]]
  target = "cart.delivery-options.transform.run"
  input_query = "src/cart_delivery_options_transform_run.graphql"
  export = "cart-delivery-options-transform-run"

  [extensions.build]
  command = ""
  path = "dist/function.wasm"
```

### src/cart_delivery_options_transform_run.graphql

```graphql
query CartDeliveryOptionsTransformRunInput {
  cart {
    deliveryGroups {
      cartLines {
        quantity
        merchandise {
          __typename
          ... on ProductVariant {
            weight
            weightUnit
          }
        }
      }
      deliveryOptions {
        handle
        title
      }
    }
  }
  deliveryCustomization {
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
```

### src/cart_delivery_options_transform_run.js

```js
// @ts-check

/**
 * @typedef {import("../generated/api").CartDeliveryOptionsTransformRunInput} CartDeliveryOptionsTransformRunInput
 * @typedef {import("../generated/api").CartDeliveryOptionsTransformRunResult} CartDeliveryOptionsTransformRunResult
 */

/** Settings stored as JSON in the customization's metafield. */
const DEFAULT_CONFIG = {
  // Total product weight per shipment, in kilograms, above which the options are hidden.
  maxWeightKg: 30,
  // Matched case-insensitively anywhere in the delivery option title.
  optionTitles: ["Express", "Ekspres"],
};

/** Kilograms per unit of Shopify's WeightUnit values. */
const KG_PER_UNIT = { GRAMS: 0.001, KILOGRAMS: 1, OUNCES: 0.028349523125, POUNDS: 0.45359237 };

/**
 * Product weight of one delivery group. Variants without a weight count as 0,
 * so missing data never hides an option by itself.
 * @param {CartDeliveryOptionsTransformRunInput["cart"]["deliveryGroups"][number]} group
 */
function groupWeightKg(group) {
  return group.cartLines.reduce((sum, line) => {
    if (line.merchandise.__typename !== "ProductVariant") return sum;
    const { weight, weightUnit } = line.merchandise;
    return sum + (weight ?? 0) * (KG_PER_UNIT[weightUnit] ?? 0) * line.quantity;
  }, 0);
}

/**
 * @param {CartDeliveryOptionsTransformRunInput} input
 * @returns {CartDeliveryOptionsTransformRunResult}
 */
export function cartDeliveryOptionsTransformRun(input) {
  const config = { ...DEFAULT_CONFIG, ...input.deliveryCustomization?.metafield?.jsonValue };
  const titles = config.optionTitles.map((title) => title.toLowerCase());

  // Each delivery group is a separate shipment, so weigh them one by one.
  const operations = input.cart.deliveryGroups
    .filter((group) => groupWeightKg(group) > config.maxWeightKg)
    .flatMap((group) => group.deliveryOptions)
    .filter((option) => titles.some((title) => (option.title ?? "").toLowerCase().includes(title)))
    .map((option) => ({ deliveryOptionHide: { deliveryOptionHandle: option.handle } }));

  return { operations };
}
```

## Test input and expected output

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

```json
{
  "cart": {
    "deliveryGroups": [
      {
        "cartLines": [
          { "quantity": 12, "merchandise": { "__typename": "ProductVariant", "weight": 900, "weightUnit": "GRAMS" } }
        ],
        "deliveryOptions": [
          { "handle": "e5f6-standard", "title": "Standart Kargo" },
          { "handle": "e5f6-same-day", "title": "Aynı Gün Teslimat" }
        ]
      }
    ]
  },
  "deliveryCustomization": {
    "metafield": { "jsonValue": { "maxWeightKg": 10, "optionTitles": ["Aynı Gün"] } }
  }
}
```

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

```json
{ "operations": [ { "deliveryOptionHide": { "deliveryOptionHandle": "e5f6-same-day" } } ] }
```

### tests/heavy-cart-in-pounds.input.json

```json
{
  "cart": {
    "deliveryGroups": [
      {
        "cartLines": [
          { "quantity": 3, "merchandise": { "__typename": "ProductVariant", "weight": 25, "weightUnit": "POUNDS" } },
          { "quantity": 1, "merchandise": { "__typename": "ProductVariant", "weight": null, "weightUnit": "KILOGRAMS" } }
        ],
        "deliveryOptions": [
          { "handle": "a1b2c3d4-standard", "title": "Standard Shipping" },
          { "handle": "a1b2c3d4-express", "title": "Express Shipping" }
        ]
      }
    ]
  },
  "deliveryCustomization": { "metafield": null }
}
```

### tests/heavy-cart-in-pounds.output.json

```json
{ "operations": [ { "deliveryOptionHide": { "deliveryOptionHandle": "a1b2c3d4-express" } } ] }
```

### tests/light-cart.input.json

```json
{
  "cart": {
    "deliveryGroups": [
      {
        "cartLines": [
          { "quantity": 2, "merchandise": { "__typename": "ProductVariant", "weight": 4.5, "weightUnit": "KILOGRAMS" } }
        ],
        "deliveryOptions": [
          { "handle": "a1b2c3d4-standard", "title": "Standard Shipping" },
          { "handle": "a1b2c3d4-express", "title": "Express Shipping" }
        ]
      }
    ]
  },
  "deliveryCustomization": { "metafield": null }
}
```

### tests/light-cart.output.json

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

## Limits and edge cases

- The weight is the variant weight from the admin times the quantity; packaging isn’t included. Variants without a weight count as zero.
- Weights in grams, ounces and pounds are converted to kilograms before the comparison.
- Each delivery group is weighed on its own, so in a split cart only the heavy shipment loses express.
- If your carrier already refuses heavy parcels, check its rates first; the Function can only hide options that checkout offers.

## Questions

### Can Shopify hide a shipping rate based on weight?

Yes, with a delivery customization Function. It reads each variant’s weight and quantity, adds them up per shipment and hides the options you name when the total is over your limit.

### Does the Function see the parcel weight with packaging?

No. It sees each variant’s weight and quantity. Add a margin to the limit if your packaging is heavy.

### Can I hide express for oversized items instead of weight?

Yes, by product tag. See the example that hides shipping rates by product tag; both can run as separate customizations.

## Shopify documentation

- [Delivery Customization Function API](https://shopify.dev/docs/api/functions/latest/delivery-customization)

## Related

- [Activate a delivery, payment or validation Function](https://lintelagency.com/resources/graphql/register-function-customization)
- [Hide shipping rates by product tag](https://lintelagency.com/resources/shopify-functions/hide-shipping-rates-by-product-tag)
- [Delivery customization: hide, rename and sort shipping options](https://lintelagency.com/journal/shopify-delivery-customization-function)
- [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.
