Skip to content
Docs

Gift with purchase

  1. Open your store’s Discounts page and click Create discount

    Create new discount image

  2. Scroll down to the Discount Kit section, which should now be available, and click Gift with purchase

    Gift with purchase in Shopify’s Select discount type list

  3. Fill in the desired settings and click Save

    Gift with purchase requirement

What the cart needs before the gift unlocks: a Minimum quantity of items, or a Minimum subtotal.

Which products count toward the requirement: all products, specific products, or collections.

Whether one-time purchases, subscriptions, or both count toward the requirement.

Products with a compare-at price don’t count toward the requirement.

Which gift items in the cart are made free:

  • Only products added via storefront widgets (e.g. gift selector) — only gifts added by Discount Kit’s gift selector or automatic gifts are free. If a customer adds the same product to the cart themselves, they pay for it.
  • Any matching product — any of the gift products in the cart is free once the requirement is met.

Discount codes always use Any matching product: the storefront widgets can’t add gifts for a code the customer enters at checkout.

Gift with purchase tiers

A discount can have up to 10 tiers, each unlocking its own gift.

How many items, or how much spend, unlocks the tier.

How many gift items the customer gets free.

The products the gift can be. Click Browse to pick them, and Edit to choose which variants count.

Open your store’s theme editor. Select App embeds in the left hand panel and then enable Gift with purchase from Discount Kit. Open up Gift with purchase’s settings using the drop-down arrow and select Automatically add single variant gift products to the cart.

Once enabled, once a customer has unlocked a Gift with Purchase discount tier that contains a single product variant it will automatically be added to the cart. For gift tiers that contain multiple variants and the customer needs to choose from among them see instructions for enabling the Gift Selector below.

Auto gift setup image

After Discount Kit adds or removes a gift, something has to re-render the cart the shopper is looking at. This is handled automatically:

  • Themes built on Shopify’s standard cart (Dawn and Horizon families, and any theme that configures Shopify.actions.updateCart) receive the gift through Shopify’s cart action. The theme re-renders its cart drawer or page in place, and Shopify dispatches the standard shopify:cart:lines-update event for anything else listening.
  • Rebuy Smart Cart is detected automatically. Gifts are written through the cart AJAX API, which Smart Cart watches, and Smart Cart re-renders itself. No setup is needed.
  • Everything else gets the gift through the cart AJAX API, and the page reloads so the cart cannot fall out of sync.

If your theme re-renders the cart itself, you have two ways to take over from the reload:

  1. Adopt Shopify’s standard cart actions. Configure Shopify.actions.updateCart in your theme and listen for shopify:cart:lines-update. Discount Kit writes gifts through the action, so your theme sees them like any other cart change and no reload happens. See Shopify’s guide to standard storefront events and actions.

  2. Use a custom event integration. In the Gift with purchase app embed, uncheck Automatic cart updates and enter an event name under Cart update event. Discount Kit dispatches that event on both document and window after every gift change instead of reloading, and your code re-renders the cart:

    document.addEventListener('my-theme:cart-updated', () => {
    // Re-render your theme's cart here
    });

Whatever the mode, Discount Kit also dispatches discount_kit:cart_changed on document after every gift change. It is informational; it never changes how the cart is refreshed.

Allowing shoppers to remove gifts:

You can allow shoppers to manually remove automatically added gifts without them being re-added to the cart. This is useful when a shopper doesn’t want a particular gift, even though they’ve qualified for it.

To enable this feature, open the Gift with purchase settings in your theme editor’s App embeds section and enable Don’t re-add manually removed gifts.

Don’t re-add manually removed gifts setting

With this setting enabled, if a shopper manually removes an automatically added gift from their cart, it will not be re-added again.

To let customers choose their gift when multiple variants are available, enable Enable gift selector in the Gift with purchase settings. You can customize the gift selector’s appearance using the styling options below this setting.

Gift selector setup image

Discount Kit quickview as the gift selector (beta)

Section titled “Discount Kit quickview as the gift selector (beta)”

With the Components app embed enabled, Use the Discount Kit quickview (beta) swaps the classic modal for the Gift Selector: one slot per gift, the tier’s products to pick from, and a single Add to cart for the lot. Two settings appear under it:

  • Add default gifts when the quickview is closed — closing without finishing keeps what the shopper picked and adds the first available option for the rest.
  • Show a “Change gifts” button in the cart — a button under the checkout button, whenever a claimed gift has a choice, that reopens the quickview to swap gifts. Its text and style (match the theme’s checkout button, or a Discount Kit button in your brand colours) are settings, and developers can place their own <dkl-change-gifts> trigger anywhere in the cart.

The details, the styling tokens and the developer hooks are on the Gift Selector pages.

For developers building custom gift experiences, Discount Kit dispatches a browser event containing gift adjustment data:

Event Name: discount_kit:gift_adjustments

This event provides a list of gift products to add to, and cart lines to remove from, the cart as a result of changes to the cart.

Event Structure:

event.detail carries add, one entry per tier that still needs gifts, and remove, the gift lines to take out:

{
add: Array<{
discountId: string
discountTitle: string
giftMarker: string // the `_dk_gift` value this tier's gift lines need
discountTier: number // 0-based; write it as `_dk_gift_tier`
quantity: number // how many gift units the tier still needs
options: Array<{ // the products the gift can be
id: number
handle: string
image: string | null
options: unknown // the product's options_with_values
priceRange: { min: number; max: number } // major units (e.g. 12.5)
title: string
anyVariant: boolean // true when any variant qualifies
variants: Array<{ // the variants that qualify
available: boolean
id: number
title: string
image: string | null
options: string[]
price: number // cents
}>
}>
}>
remove: {
[lineKey: string]: 0 // cart line keys to set to 0
}
}

Important: Gift lines need two line item properties, which is how the discount function and the embed recognise them:

  • _dk_gift: the add’s giftMarker — the discount title for a gift with purchase, the discount’s own id for a tiered rewards gift offer
  • _dk_gift_tier: the add’s discountTier, as a string

add also covers the gift offers of tiered rewards discounts; they’re added and removed exactly like gift with purchase gifts. remove lists every gift line whose discount is no longer active, or whose tier the cart no longer reaches.

Example Usage:

document.addEventListener('discount_kit:gift_adjustments', async (event) => {
const { add, remove } = event.detail
// Remove gifts that no longer apply
if (Object.keys(remove).length > 0) {
await fetch('/cart/update.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ updates: remove }),
})
}
// Add each tier's gift — here, the first available variant of its first product
const items = add.flatMap((tier) => {
const variant = tier.options[0]?.variants.find((v) => v.available)
if (!variant) return []
return [
{
id: variant.id,
quantity: tier.quantity,
properties: { _dk_gift: tier.giftMarker, _dk_gift_tier: String(tier.discountTier) },
},
]
})
if (items.length > 0) {
await fetch('/cart/add.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ items }),
})
}
})