UpCart Free Gift Reward Loop with Shopify Automatic Discount - RESOLVED

I wanted to share this in case it saves another Shopify merchant some time.

I was setting up a free gift threshold in UpCart. The goal was simple: when the cart reached $100, UpCart would automatically add a Mystery Gift.

The problem: UpCart adds the product to the cart, but it does not make the product free. Per UpCart’s documentation, the price has to be handled in Shopify.

At first, I tried using a Shopify Buy X, Get Y automatic discount to make the gift free. This created a loop:

  1. Cart reached the UpCart reward threshold.
  2. UpCart added the gift product.
  3. Shopify automatic discount made the gift free.
  4. Cart subtotal recalculated.
  5. UpCart no longer saw the cart as qualifying.
  6. UpCart removed the gift.
  7. The discount disappeared.
  8. UpCart added the gift again.

So the gift kept adding and removing itself from the cart.

Resolution — the stable fix:

  1. Duplicate the gift product in Shopify.
  2. Set the duplicate product price to $0.00.
  3. Set the product to Active and publish it to the Online Store channel only.
  4. Use that $0 product as the UpCart reward product.
  5. Disable/remove the Shopify automatic discount for the gift.
  6. Set Shopify’s seo.hidden metafield on the $0 gift product so it does not appear in SEO/search.
  7. Make sure the metafield is active for the relevant access/options, including API, Analytics, and Smart Collections, so the product is not exposed in storefront collections.
  8. If using Shopify’s default “All Products” collection, be aware that the seo.hidden metafield does not necessarily remove the product from that default collection. I had to replace/adjust All Products as a smart collection so the free gift product would not appear publicly.
  9. I created a new smart collection titled “All Products” and changed the URL handle to /collections/all.

After switching to the duplicate $0 product, UpCart could add the reward at the threshold without triggering the Shopify discount/subtotal loop.

Hopefully this helps someone else setting up UpCart free gift rewards. Before finding this solution, I experienced similar behavior while testing other cart apps as well. In my case, the issue was not the app itself; it was the setup.

I am grateful for UpCart because their documentation got me 90% of the way there, but the seo.hidden metafield and the All Products smart collection pieces were a self-discovery process.

Glad you found a workaround, but honestly this is a lot of duct tape for something that should just work out of the box. Creating a $0 duplicate, hiding it via seo.hidden metafield, rebuilding your All Products collection as a smart collection, all to avoid a loop that shouldn’t exist in the first place.

The root issue is that UpCart separates the “add product to cart” step from the “make it free” step and offloads the pricing to Shopify’s native discount system. That’s what creates the loop: Shopify discount lowers the cart total, cart no longer qualifies for the gift, gift gets removed, total goes back up, gift gets re-added, repeat forever.

Apps that handle both the add-to-cart and the pricing in one operation don’t have this problem. BOGOS does this: when the cart hits your threshold, it adds the gift AND applies the $0 price as part of the same action, so the subtotal calculation doesn’t trigger a loop. If the customer drops below the threshold, the gift gets removed cleanly. No duplicate products, no metafield tricks, no collection rebuilding.

Not saying you need to switch since your setup is working now, but if anyone else lands on this thread looking for a simpler path, that’s the difference to look for. The app needs to own both the trigger and the pricing, not hand one off to Shopify’s discount engine.

Best,
Moeed

Hi @Mary_Ann_Nicholson .
The loop you hit is a known conflict between Cart apps and Shopify’s valid discount recalculating the subtotal.
Using a $0 dupliacte product sidesteps it cleanly.
The seo.hidden Metafield and a smart collection workaround for the default /collection/all are especially useful since that last price was not documented anywhere.