Key takeaways
- Shopify can make a gift free, but it will not put it in the cart. A Buy X Get Y discount only applies once the customer has added the gift themselves.1
- There are three ways to close that gap: clear messaging, theme code that adds and removes the gift through the Cart AJAX API, or an app.
- Fudge writes that theme code from a prompt. You describe the gift rule and it adds the add-and-remove logic to your cart as native theme code.
- The discount always lives in the Shopify admin. Theme code only moves the item into the cart. Buy X Get Y is what takes it to $0.
- Simple spend tiers work natively with one automatic discount per tier, as long as the tiers are not set to combine with each other.
A Shopify free gift with purchase takes one native discount to set up, and it has one gap that often surfaces only after launch: Shopify makes the gift free, but the customer has to add it to the cart themselves. This guide covers the native setup, three ways to get the gift into the cart, and the edge cases merchants ask about.
It is timed for Black Friday 2026 (27 to 30 November) but works for any promotion. Still choosing the offer? Black Friday sale ideas for Shopify stores compares a gift against the other mechanics on margin.
Why you can trust us
We have been in the Shopify space for over four years and have worked with hundreds of Shopify brands on their storefronts. Jacques has over 15 years of development experience. We build Fudge, an AI storefront editor with a 4.9 rating on the Shopify App Store and Built for Shopify status, and cart drawer logic like the gift code in this guide is the kind of theme work it writes.
How does a free gift with purchase work natively in Shopify?
Shopify has no discount type called “free gift”. The native route is a Buy X Get Y discount with a spend or quantity trigger and a reward set to free.1
Create it as a Shopify automatic discount and there is no code for the customer to enter. Automatic discounts apply in the cart and at checkout when the conditions are met.2
How to set up the Buy X Get Y discount
- In your Shopify admin, go to Discounts and click Create discount.
- Choose Buy X get Y, then under Method select Automatic discount and enter a title. Dawn prints the discount title next to the discounted line in the cart, so write it for customers.
- Under Customer buys, choose Minimum purchase amount (for example $75) or Minimum quantity of items, then select the products or collections that count toward it.
- Under Customer gets, set the quantity to 1, select the gift product or a gift collection, and under At a discounted value choose Free.
- Check Set the maximum number of uses per order and enter 1, so the promotion applies once per order.
- Set Combinations and the active dates, then click Save.
The minimum purchase amount counts product prices only. Shipping and taxes are excluded, and products count at full price before any other discount.1
Because you choose which products count, keep the gift itself out of that selection so its own price cannot help a cart qualify. For where to set the number, see our guide to setting a free shipping threshold - the same logic applies.
What are the limits?
- 25 active automatic discounts per store, counting amount off, Buy X Get Y, free shipping and app-based automatic discounts together.2
- Combinations are opt-in. Buy X Get Y is a product discount. It runs alongside an order discount or a free shipping discount only when the matching Combinations boxes are checked on both.3
- Products in a Buy X Get Y discount cannot take a second product discount on plans below Shopify Plus.3 A sitewide sale built as a product discount competes with the gift instead of stacking with it.
- When discounts cannot combine, Shopify applies the one that is best for the customer’s cart.3 A discount code can win and leave the gift at full price, so run a test cart with every discount you plan to have live.
Why doesn’t Shopify add the free gift to the cart automatically?
Because a discount changes prices, not cart contents. Shopify’s help page is direct about it: “The free or discounted ‘get’ item is never automatically added to the cart.”1
A shopper who spends $80 and goes straight to checkout gets no gift, no error, and no hint that one was on offer. There are three ways to close the gap.
Method 1: Tell the customer clearly (no code)
The cheapest fix is copy. Say what the gift is, what the threshold is, and that it has to be added - on the product page, in the cart and in the announcement bar - and link straight to the gift product.
The weakness is plain: some shoppers will not read it. A message that reacts to the cart is harder to miss than a static line. It works like a free shipping bar that updates with the cart: read the cart total, compare it with the threshold, show the difference.
The Fudge route. Fudge writes that message into your cart drawer and product page as native theme code. Tell Fudge:
“Add a gift progress message to the cart drawer and the product page. Under $75 it says ‘You’re $12 away from a free travel-size cleanser’ using the real remaining amount. At $75 or more it shows the cleanser with an ‘Add my free gift’ button.”
You get a draft to preview and review before publishing. The Buy X Get Y discount still does the discounting.
Method 2: Add the gift with theme code
Shopify’s Cart AJAX API lets theme JavaScript change the cart: a POST to /cart/add.js adds a variant, and a POST to /cart/change.js with a quantity of 0 removes a line.4 A short script can add the gift when spend reaches the threshold and take it out when spend falls back.
Duplicate your theme first. Then go to Online Store → Themes → ⋯ → Edit code, create snippets/free-gift.liquid, and paste this in with your own threshold and variant ID. The ID is the number after /variants/ in the admin URL when you open the variant; for a product without variants, add .json to the product’s admin URL and read the variant ID there.
<script>
document.addEventListener('DOMContentLoaded', function () {
var GIFT_VARIANT_ID = 41234567890123 // your gift variant ID
var THRESHOLD = 7500 // $75.00 - the Cart API works in cents
var root = window.Shopify.routes.root
var busy = false
function post(path, body) {
return fetch(root + path, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(body),
})
}
function syncGift() {
if (busy) return
busy = true
fetch(root + 'cart.js')
.then(function (response) {
return response.json()
})
.then(function (cart) {
var gift = null
var spend = 0
cart.items.forEach(function (item) {
if (item.variant_id === GIFT_VARIANT_ID) gift = item
else spend += item.original_line_price
})
var offered = sessionStorage.getItem('giftOffered') === '1'
if (gift) sessionStorage.setItem('giftOffered', '1')
if (spend >= THRESHOLD && !gift && !offered) {
sessionStorage.setItem('giftOffered', '1')
return post('cart/add.js', {
items: [{id: GIFT_VARIANT_ID, quantity: 1}],
})
}
if (spend < THRESHOLD) {
sessionStorage.removeItem('giftOffered')
if (gift) return post('cart/change.js', {id: gift.key, quantity: 0})
}
})
.then(function (response) {
// Dawn: ask the cart drawer or cart page to re-render
if (response && response.ok && window.publish) {
publish(PUB_SUB_EVENTS.cartUpdate, {source: 'free-gift'})
}
})
.catch(function (error) {
console.error(error)
})
.finally(function () {
busy = false
})
}
// Dawn announces every cart change on this event
if (window.subscribe) {
subscribe(PUB_SUB_EVENTS.cartUpdate, function (event) {
if (event && event.source === 'free-gift') return
syncGift()
})
}
syncGift()
})
</script>
Then load the snippet just before the closing body tag in layout/theme.liquid:
{% render 'free-gift' %}
The script totals every line except the gift at its pre-discount price, mirroring how the discount counts the minimum. The giftOffered flag stops it adding the gift twice, re-adding one the customer removed, or retrying a sold-out gift.
The script only moves the item. The Buy X Get Y discount is still what makes it free, so the two thresholds must match. If the script’s number is lower, customers find a full-price item in the cart.
Know its edges before you ship it:
- It is wired for Dawn.
subscribeandpublishare Dawn’s cart event helpers, and Dawn’s cart drawer re-renders its lines and footer when that event fires.5 Other themes announce cart changes differently, so those lines need rewriting. - The header cart count can lag. Dawn’s handler refreshes the drawer, not the cart icon.
- It counts every non-gift line. If only some products qualify for your discount, the loop has to filter to those.
- It assumes one currency. If you sell in several, test the gift in each market.
The Fudge route. Fudge does this for you: it writes the add-and-remove logic for your theme’s cart, so there is nothing to hand-code and no rewiring per theme. Tell Fudge:
“When the cart subtotal reaches $75, automatically add the free travel-size cleanser to the cart and show a ‘Free gift added’ line in the cart drawer. Remove it if the cart drops below $75, and don’t add it twice.”
Fudge writes the cart drawer logic as native Liquid, CSS and JavaScript in your theme, as a draft you review before publishing. The discount that makes the gift $0 is still the Buy X Get Y discount you create in the Shopify admin - Fudge does not create or configure discounts.
Method 3: Use an app or a Shopify Function
Gift apps package Method 2 behind a settings screen: you pick the gift and the threshold, and the app adds the item to the cart. Check the live App Store listing for current plans.
The trade is a monthly fee plus app code on your storefront, because something has to run in the browser to add the item. If you already use an app for cart upsells, check whether it covers gifts before adding another.
Shopify Functions fit less well than they sound. Discount Functions decide what cart lines cost, and the Cart Transform API expands, merges or updates lines already in the cart. Neither reference describes an operation that drops a separate new item into it.6
Stores on any plan can use Functions through a public App Store app; custom apps that contain Functions require Shopify Plus.6
Which free gift with purchase method should you use?
| Method | Cost | Adds the gift? | Removes it below the threshold? | Effort |
|---|---|---|---|---|
| Buy X Get Y + clear messaging | Included in Shopify | No, the customer adds it | No - it stays at full price | Low |
| Buy X Get Y + hand-written theme code | Developer time | Yes | Yes, if you code it | High, theme-specific |
| Buy X Get Y + Fudge | Fudge plan | Yes | Yes, when the prompt asks for it | Low - a prompt and a review |
| Gift app | Monthly fee, see the listing | Yes | Confirm on the listing | Low to medium |
Do the messaging whichever row you pick. The Shopify store editor page shows how the Fudge route works.
What edge cases should you plan for?
What happens when the gift is out of stock?
Turn on Inventory tracked for the gift variant and leave Continue selling when out of stock unchecked. At zero stock customers cannot buy it, the add request from Method 2 is rejected with a 422 error, and orders go through without a gift.4
Your messaging does not update itself, so pull the banner when the gift runs out, or point Customer gets at a gift collection so a second item can stand in.
What if the cart drops below the threshold?
The discount stops applying. The gift does not leave the cart on its own - it stays there at full price. The Method 2 script removes it; with Method 1, the cart message should say the gift is no longer free.
What if the customer removes the gift?
Let them. The script above adds the gift once, and not again until the cart has dropped below the threshold and come back.
Can customers choose their gift?
Yes. Customer gets accepts a collection, so any item in it can be the free one. Auto-add cannot guess a shade or a size, so a choice needs a picker. If the gift is really part of a set, compare native Shopify bundles vs bundle apps.
The Fudge route. Tell Fudge:
“When the cart reaches $75, show a ‘Choose your free gift’ block in the cart drawer with the three products from my Free Gifts collection. Let the customer pick one, add it to the cart, and let them swap it for another.”
The result is a native theme block in draft. Set the discount’s Customer gets to the same collection.
How do you stop the gift being bought on its own for free?
Give the gift product a real price. The discount only takes it to $0 when the minimum is met, so on its own it sells at full price. A product priced at $0 can be added by anyone.
What happens when the qualifying item is returned?
The discount pages we checked describe no automatic recovery of the gift, so treat it as a policy decision. State in your returns policy whether the gift must come back or its value is deducted.
How does the gift show on the order?
As a regular line item with its own SKU, discounted to $0. A real product with tracked inventory reaches picking and packing like any other line.
Spend more, save more: what about tiered discounts?
Shopify tiered discounts have no dedicated discount type. Shopify’s help page sends merchants who need advanced tiered discounts to the App Store, or to Checkout Blocks on Shopify Plus.7
Simple spend tiers can still be assembled from native parts. Create one automatic amount off order discount per tier, each with its own minimum purchase amount:
- Tier 1: 10% off, minimum purchase $100
- Tier 2: 20% off, minimum purchase $200
Under Combinations, leave order discounts unchecked on both. A cart that qualifies for two discounts that cannot combine gets the one that is best for the customer.3
Worked example. A $230 cart qualifies for both tiers. They cannot combine, so the 20% tier applies: $46 off, $184 to pay. A $150 cart reaches only the first tier: $15 off, $135 to pay.
The trap is the combination box. If the tiers are allowed to combine, both percentages are calculated on the original subtotal, so that $230 cart gets 30% off and pays $161.3
Each tier uses one of your 25 automatic discount slots.
What still needs an app or a discount Function: tiers managed as a single discount, and one discount that mixes rewards such as a percentage off plus free shipping.7 To run tiers alongside the free gift, check product discounts on each tier and order discounts on the Buy X Get Y discount, then test a cart at every tier boundary.
Our BFCM playbook covers where to show the tiers on the storefront.
FAQ
No. A Buy X Get Y discount makes the gift free, but the customer has to add the gift to the cart before the discount applies. To add it automatically you need theme code that uses the Cart AJAX API, which Fudge can write from a prompt, or an app that does the same job.
In your Shopify admin go to Discounts, create a Buy X get Y discount, choose Automatic discount, set a minimum purchase amount under Customer buys, select the gift under Customer gets, and choose Free. Then tell customers to add the gift, or add theme code that puts it in the cart when the threshold is reached.
The usual causes are that the gift is not in the cart, the qualifying products are below the minimum, or the items are not in the collections the discount names. Another discount can also win: when discounts cannot combine, Shopify applies the one that is best for the customer's cart.
Yes. Point the Customer gets part of the discount at a collection of gifts and any item in that collection can be the free one. Because automatic add-to-cart cannot guess a shade or a size, a gift choice needs a picker in the cart or on the product page.
The discount stops applying and the gift stays in the cart at full price. Shopify does not remove it. Theme code or an app has to remove the gift line, or your cart message has to tell the customer it is no longer free.
Simple spend tiers, yes. Create one automatic amount off order discount per tier with its own minimum purchase amount, and do not let them combine with each other, so the best one applies to each cart. Tiers managed inside a single discount need an app or a discount Function.
Up to 25 active automatic discounts per store, including Buy X Get Y, amount off, free shipping and app-based automatic discounts. A free gift uses one of them, and each native spend tier uses one more.
Footnotes
-
Shopify Help Center, “Buy X get Y discounts” - customers must add all items to the cart manually and the “get” item is never added automatically; the minimum purchase amount counts product prices only, excludes shipping and taxes, and counts products at full price before other discounts; the reward can be a percentage, an amount off each, or free, with an optional maximum number of uses per order. https://help.shopify.com/en/manual/discounts/discount-types/buy-x-get-y ↩ ↩2 ↩3 ↩4
-
Shopify Help Center, “Automatic discounts” - automatic discounts apply in the cart and at checkout when eligibility conditions are met, can be amount off, free shipping, Buy X Get Y or app-based, and a store can have a maximum of 25 active at once. https://help.shopify.com/en/manual/discounts/discount-methods/automatic-discounts ↩ ↩2
-
Shopify Help Center, “Combining discounts” - discounts combine only when their combination settings allow it; products in a Buy X Get Y discount are ineligible for further product discounts outside Shopify Plus; when discounts cannot combine, the best discount for the customer’s cart applies; two percentage order discounts that do combine are both calculated on the original subtotal. https://help.shopify.com/en/manual/discounts/discount-combinations ↩ ↩2 ↩3 ↩4 ↩5
-
Shopify developer documentation, “Cart API reference” -
/cart/add.jsadds variants from anitemsarray and returns a 422 error when the product is sold out;/cart/change.jsaccepts a line item key or variant ID and removes the line when quantity is 0;/cart.jsreturns prices in cents; requests should be built fromwindow.Shopify.routes.root. https://shopify.dev/docs/api/ajax/reference/cart ↩ ↩2 -
Shopify, Dawn theme source,
assets/cart.js- the cart items and cart drawer items elements subscribe to the theme’s cart update event and re-fetch their section when it fires from another source; the drawer handler replaces the drawer items and footer. https://github.com/Shopify/dawn/blob/main/assets/cart.js ↩ -
Shopify developer documentation, “Shopify Functions” - stores on any plan can use public App Store apps that contain Functions, and only Shopify Plus stores can use custom apps that contain them (https://shopify.dev/docs/apps/build/functions). The Cart Transform Function API reference lists three operations, which expand, merge and update cart lines (https://shopify.dev/docs/api/functions/latest/cart-transform). ↩ ↩2
-
Shopify Help Center, “Discount types” - for more advanced needs such as tiered discounts the page points to discount apps on the Shopify App Store, or Checkout Blocks on Shopify Plus, and notes that apps can provide a single discount that applies more than one saving to an order. https://help.shopify.com/en/manual/discounts/discount-types ↩ ↩2