Function input.cart.attribute doesn't map to the AJAX cart attributes

Hi there,

My end goal is to trigger a discount on checkout conditionally based on piece of metadata.

I want to make this discount function to be usable by Plus and non-Plus stores.

So I thought that the Input cart.attribute field might the the trick.

So as a test, on the online storefront I created a sample attribute on the cart discount_qualified:

fetch('/cart/update.js', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    attributes: {
      discount_qualified: 'true'
    }
  })
})
.then(response => response.json())
.then(data => {
  console.log('Cart attribute updated:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

And I set up an input schema like so:

query CartInput {
  cart {
    attribute(key: "discount_qualified") {
      value
    }
  }
}

I also ran shopify app function typegen to make sure the schema was updated.

And finally, I created and activated discount function using the cart attribute to qualify the checkout for a discount:


import {
  OrderDiscountSelectionStrategy,
  ProductDiscountSelectionStrategy,
  CartInput,
  CartLinesDiscountsGenerateRunResult,
} from "../generated/api";

export function generateCartRun(
  input: CartInput
): CartLinesDiscountsGenerateRunResult {
  console.log("starting function");
  console.log("input", JSON.stringify(input, null, 2));

  console.log(
    `discount_qualified value: ${input.cart?.attribute?.value}`
  );

  const isQualified = input.cart.attribute?.value === "true";

  if (!isQualified) {
    return {
      operations: [],
    };
  }

  return {
    operations: [
      {
        orderDiscountsAdd: {
          candidates: [
            {
              message: "10% OFF ORDER",
              targets: [
                {
                  orderSubtotal: {
                    excludedCartLineIds: [],
                  },
                },
              ],
              value: {
                percentage: {
                  value: 10,
                },
              },
            },
          ],
          selectionStrategy: OrderDiscountSelectionStrategy.First,
        },
      }
    ],
  };
}

But the cart.attribute value is null.

Are cart attributes accessible to the discount function not the same as the Online Store AJAX Cart API attributes?

If they aren’t then how can one update them?

I’d really like to be able to offer a discount function to Plus and non-Plus stores.

My latest guess is that the discount function’s input cart.attribute option only maps to attributes created by Checkout Extensions applyAttributeChange hook:

I have yet to confirm this, but that’s my leading hunch.

That would be a bummer if there’s no way to trigger a discount function for a non-Plus store (assuming guest checkout, asking customers to register first would be a conversion killer).

Quick update - cart attributes only map when the customer is logged in.

This means that guest check cart attributes created through the AJAX API are not present in the function run input.

This seems like a bug to me. Cart Attributes can be created for a guest session or a logged in customer session, and they should be available during checkout for either.

For more context, I’m using the Discount Function API (2025-04) to create and register the discount function, and the standard online store AJAX API to create the attribute.

After recreating the discount function from scratch, registering it, and recreating the cart attributes I can confirm the guest checkouts map cart attributes to the discount function run inputs.

Could have been user error, or just some edge case when I was switching package managers in order to generate the extension correctly. Not sure.

But it looks like the API is working as expected. All good!

Unfortunately the issue has cropped up once again.

I’ve made a screencast to show the problem in real time. The cart attribute can be read by the discount function on product pages, but not the checkout page itself with a guest checkout.

I’m going to try an app build/deploy to rule out some deployed vs shopify app dev state behavior. But regardless the run input should be able to read cart attributes in the checkout page too.

Update: rebuilding a deploying the extension makes no difference. The cart attribute isn’t exposed to the checkout guest sessions.

I switched to using a public cart attribute instead of a private attribute (removing the _ prefix in the attribute key).

That seems to work, for now. But if it crops up again I’ll share more details.

Update it stopped working once again, but thanks to @David-Shopify I’ve narrowed down that this bug is only affecting the Buy it Now button a.k.a. accelerated checkout.

If I do the classic Cart > Checkout flow, then the cart attributes are present.

There seems to be some kind of issue with cart attributes failing to be passed in the Buy it Now flow intermittently.

1 Like