The objective is to automatically add a secondary product to the customer's cart when they add a primary product, using a "Buy X Get Y" discount structure.
The standard challenge with "Buy X Get Y" discounts is that they require customers to manually add both the purchased item and the free item to their cart. This creates friction in the user experience.
This approach bypasses that limitation by automatically adding the free item when the main product is purchased.
Example use case: During a campaign, when a customer adds a perfume to their cart, a free sample of the same perfume is automatically added and discounted to $0.
The solution uses Shopify's "Buy X Get Y" discount with specific configuration settings to achieve this automatic behavior.
Discount Setup
To implement this functionality, the discount must be configured as follows:
Basic Settings:
Type: Buy X Get Y (Product discount)
Automatic: Must be set to "Automatic" - this is crucial for the auto-add functionality
Customer Buys Section:
Select "Minimum quantity of items"
Set quantity to 1
Choose the trigger product (e.g., "Perfume 1")
Customer Gets Section:
Set quantity to 1
Select the free product to be auto-added (e.g., "Perfume 1 trial")
Set discount value to "Free"
Usage Limits:
Set maximum uses per order to 1 (prevents multiple free items)
Combinations:
Product discounts: Optional, but recommended if:
You're running multiple auto-add offers simultaneously
You want to allow other product-level discounts to work alongside this offer
Order discounts: Consider enabling if you use:
Influencer discount codes
Site-wide promotional codes
Any other order-level discounts that should be combinable with this auto-add offer
The automatic setting ensures that when the trigger product is added to cart, the system immediately applies the discount and adds the free product without requiring customer action.
If you run multiple such offers at the same time, create a separate Buy X Get Y discount for each product-gift combination.
Before you can start prompting, we must find both the product ID of the product we want to use as a trigger (the normal Perfume) and the variant ID of the product we want added to cart automatically. Learn how to do this here:
How to: Find a product's variant ID
Learn how to find a product's variant ID
We use the following prompt for our AI to create the custom HTML:
I want to check the items in cart for product ID 10046673027351. If that one is in the cart, I want to add a product with variant ID 51374537146647. And similarly if product ID 10046679941399 is in the cart, then add variant ID 51374542717207. Quantity of the auto-added is always 1. Make sure to not re-add if already in cart.
<div id="auto-add-products" class="tw-hidden">
<script>
(function() {
const PRODUCT_VARIANT_MAPPING = {
'10046673027351': '51374537146647',
'10046679941399': '51374542717207'
};
let isProcessing = false;
async function checkAndAddProducts(cartData) {
if (isProcessing || !cartData || !cartData.items) return;
try {
isProcessing = true;
const cartItems = cartData.items || [];
const cartProductIds = new Set();
const cartVariantIds = new Set();
// Collect product IDs and variant IDs currently in cart
cartItems.forEach(item => {
if (item.product_id) cartProductIds.add(item.product_id.toString());
if (item.variant_id) cartVariantIds.add(item.variant_id.toString());
if (item.id) cartVariantIds.add(item.id.toString());
});
// Check each mapping
for (const [productId, variantId] of Object.entries(PRODUCT_VARIANT_MAPPING)) {
const shouldAdd = cartProductIds.has(productId) && !cartVariantIds.has(variantId);
if (shouldAdd) {
try {
// Use fetch to add to cart via Shopify Cart API
const response = await fetch('/cart/add.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: variantId,
quantity: 1
})
});
if (response.ok) {
// Trigger cart refresh after successful add
if (window.EliteCart && typeof window.EliteCart.refreshCart === 'function') {
await window.EliteCart.refreshCart();
} else {
// Alternative method to refresh cart
const cartResponse = await fetch('/cart.js');
if (cartResponse.ok) {
const updatedCart = await cartResponse.json();
if (window.EliteCart && typeof window.EliteCart.updateCart === 'function') {
window.EliteCart.updateCart(updatedCart);
}
}
}
}
} catch (addError) {
console.warn('Failed to auto-add variant:', variantId, addError);
}
}
}
} catch (error) {
console.warn('Error in auto-add products:', error);
} finally {
isProcessing = false;
}
}
// Initial check
const initialCart = window.EliteCart?.getCurrentCart?.();
if (initialCart) {
setTimeout(() => checkAndAddProducts(initialCart), 500);
}
// Listen for cart changes
if (window.EliteCart && typeof window.EliteCart.onCartChange === 'function') {
window.EliteCart.onCartChange((cartData) => {
setTimeout(() => checkAndAddProducts(cartData), 300);
});
}
})();
</script>
</div>
The current implementation has several limitations / choices that may affect the user experience:
Sample remains after removing main product: If a customer removes the perfume from their cart, the free sample stays in the cart but loses its discount, meaning it would be charged at full price.
Sample cannot be manually removed: Customers cannot manually delete the free sample from their cart as it gets automatically re-added by the discount logic.
Single sample regardless of quantity: Even if a customer adds multiple units of the same perfume, they still receive only one free sample (limited by both the discount setup and the script)
Mitigation Strategies:
These limitations can be addressed using the AI editor. For the first and third limitations, implement cart monitoring that automatically removes orphaned samples when the main product is removed, and adds additional samples proportional to the main product quantity.
For the second limitation, the AI editor should be instructed to set a flag in session storage when a customer manually attempts to remove the sample. This flag can then be checked before the auto-add logic runs, preventing the unwanted re-addition of the sample.