How to Automatically Apply Multiple Discount Codes in Shopify (Step-by-Step Guide)
by Jay B, Shopify Expert
Save time and delight shoppers! This Shopify tutorial shows you how to automatically apply multiple discount codes from a URL and persist them using cookies; perfect for marketing campaigns, collaborations, and special offers.
Note
This tutorial was created using the latest version (3.0.0) of Shopify’s Horizon theme.
The logic may differ slightly if your theme uses a custom cart setup or older architecture.
Creating discount-codes.js for URL-Based Persistent Discounts 🔗
This script automatically applies discount codes found in a URL parameter and saves them in a cookie.
Customers will retain these discounts as they browse your store, even if they leave the cart page.
Step 1: Create the discount-codes.js Asset
File path:
/assets/discount-codes.js
In your Shopify theme editor, navigate to the Assets folder and create a new blank file named discount-codes.js.
Paste the following code inside:
import { fetchConfig } from '@theme/utilities';
import { CartUpdateEvent } from '@theme/events';
function applyDiscounts() {
// Cookie helpers
function getCookie(name) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? decodeURIComponent(match[2]) : null;
}
function setCookie(name, value, days = 1) {
const expires = new Date(Date.now() + days * 864e5).toUTCString();
document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/`;
}
// Get discounts from URL
const urlParams = new URLSearchParams(window.location.search);
const discountsFromUrl = urlParams.get('discounts')
? urlParams.get('discounts').split(',').map(d => d.trim())
: [];
// Get stored discounts
const cookieDiscounts = getCookie('discount_codes')
? getCookie('discount_codes').split(',').map(d => d.trim())
: [];
// Check if URL discounts differ from cookie discounts
const areDifferent =
discountsFromUrl.length !== cookieDiscounts.length ||
discountsFromUrl.some(d => !cookieDiscounts.includes(d));
// If new discounts are in the URL, store them in the cookie
if (discountsFromUrl.length && areDifferent) {
setCookie('discount_codes', discountsFromUrl.join(','));
}
// If no discounts in URL or cookie, stop
if (!cookieDiscounts.length && !discountsFromUrl.length) return;
// Determine final discounts to apply
const finalDiscounts = discountsFromUrl.length ? discountsFromUrl : cookieDiscounts;
// Fetch cart and apply missing discounts
const config = fetchConfig('json', {});
fetch(Theme.routes.cart_url, { ...config })
.then(res => res.json())
.then(cart => {
const activeDiscounts = (cart.discount_codes || []).map(d => d.code.toLowerCase());
const missingDiscounts = finalDiscounts.filter(
d => !activeDiscounts.includes(d.toLowerCase())
);
if (missingDiscounts.length) {
const discountsToApply = [
...new Set([...activeDiscounts, ...missingDiscounts.map(d => d.toLowerCase())])
];
// Collect cart section IDs for updated render
const cartItemsComponents = document.querySelectorAll('cart-items-component');
const cartItemComponentsSectionIds = Array.from(cartItemsComponents)
.filter(el => el instanceof HTMLElement && el.dataset.sectionId)
.map(el => el.dataset.sectionId);
// Prepare the cart update request
const updateConfig = fetchConfig('json', {
body: JSON.stringify({
discount: discountsToApply.join(','),
sections: cartItemComponentsSectionIds.join(','),
}),
});
// Send the update request
fetch(Theme.routes.cart_update_url, updateConfig)
.then(res => {
if (!res.ok) throw new Error('Failed to apply discounts');
return res.json();
})
.then(cartData => {
console.log('Applied missing discounts:', missingDiscounts);
document.dispatchEvent(
new CartUpdateEvent({}, 'discount-codes', {
source: 'discount-codes',
sections: cartData.sections,
})
);
})
.catch(err => console.error('Error applying discounts:', err));
} else {
console.log('All URL/cookie discounts already active.');
}
})
.catch(err => console.error('Error fetching cart:', err));
}
applyDiscounts();What’s Happening in This Code
Cookie Helpers (getCookie & setCookie)
These functions allow the script to read and store discount codes in the customer’s browser:
getCookiereads existing discounts so we don’t reapply the same ones.setCookiesaves new discounts, so they persist as the customer navigates the store.
Reading Discounts from the URL
The script checks if the URL contains a ?discounts=CODE1,CODE2 parameter:
- Multiple codes are split into an array for easier processing.
- Trimming ensures no extra spaces cause issues.
Comparing URL Discounts to Cookie Discounts
- If the discounts in the URL differ from those already in the cookie, the cookie is updated.
- This prevents unnecessary reapplication of the same discounts.
Determining Which Discounts to Apply
finalDiscountschooses URL discounts first, falling back to the cookie if no URL parameter is present.- Ensures new discount links always take priority.
Fetching the Cart and Applying Discounts
- Uses
fetchand Shopify’s AJAX Cart API (Theme.routes.cart_url) to get the current cart. - Compares
finalDiscountstocart.discount_codesto see what’s missing. - Missing codes are added while preserving any existing cart discounts, and the cart UI is updated dynamically using
CartUpdateEvent.
Dispatching the Cart Update Event
- Triggers Shopify’s cart rendering system to refresh affected sections without a full page reload.
- This is what makes the discounts appear instantly for the customer.
Top tip
The cookie expires after 1 day by default, but you can increase this duration by changing the days value in setCookie().
Reference: Learn more about Shopify’s AJAX Cart API and the cart/change.js endpoint in the official docs —
Step 2: Link the Script in theme.liquid
Open Layout → theme.liquid, scroll to the bottom, and insert this before the closing </body> tag:
<script
src="{{ 'discount-codes.js' | asset_url }}"
type="module"
defer
fetchpriority="low"
></script>Note
Using type="module" ensures the ES6 imports (like fetchConfig) are handled correctly.
Final Testing and Usage
After saving all changes and ensuring your discount codes are active and published in Shopify Admin, test with a link like this:
https://your-store-name.myshopify.com/?discounts=SAVE10,SHIPFREE
- The codes
SAVE10andSHIPFREEwill be automatically applied to the cart. - They’ll persist until the cookie expires or the user visits another discount link.
Troubleshooting
Discounts not applying?
Make sure all discount codes are active and can be combined in Shopify’s discount settings.
Cookie not persisting?
Some browsers block third-party cookies — test in a private window or increase the expiration time in the script.
Cart not updating?
Confirm your theme supports fetchConfig and CartUpdateEvent.
If not, adjust the cart update logic accordingly.
How This Tutorial Came to Be
The idea for this tutorial was born out of a real-world need I encountered almost a year ago while working on a client store.
Initially, I thought this would be a quick tutorial, but I soon realized my old solution, using the checkout URL /checkout?discount=SAVE10,SHIPFREE no longer worked reliably.
This discovery led me to develop a new, much better solution: a simple, reliable way to automatically apply multiple discount codes via a URL, perfect for marketing campaigns and influencer collaborations.
Shopify doesn’t natively support applying multiple discounts via a single URL, so I created this lightweight JavaScript approach to bridge that gap.
There’s room for further enhancements — for example, it could easily be extended to add products to the cart directly from the link as well.
Summary
You’ve now implemented a lightweight, automatic multi-discount system for Shopify that:
- Applies discounts directly from URL parameters
- Persists them across sessions with cookies
- Updates the cart dynamically without page reloads
Perfect for influencer campaigns, partnerships, and seamless promotional experiences that boost conversions.
🚀 Advanced Customisation & Consulting
You've successfully implemented a persistent, multi-discount system! For merchants looking to turn this feature into a full, high-conversion marketing automation tool, the next step is integrating advanced logic and front-end displays.
These complex integrations require deep knowledge of Shopify's Liquid, JavaScript, and Cart APIs. If you are ready to scale this system, these are the high-impact projects I can help you implement:
1. 🛒 URL-to-Cart Automatic Product Addition
Combine the discount link with product provisioning for a truly seamless campaign experience.
-
The Upgrade: Modifying the JavaScript logic to recognise a second URL parameter (e.g., &adds=SKU1:qty,SKU2:qty).
-
The Logic: Extending the fetch sequence to first use the /cart/add.js endpoint to ensure the necessary products are in the cart before applying the associated discount codes.
-
The Goal: Simplify flash sales or collaboration campaigns by letting customers click one link to get the product, the discount, and a pre-loaded cart—removing all friction.
2. 🪟 Front-End Discount Display & Removal
Give users control and clarity by visually showing which codes were applied and offering a quick way to remove them.
-
The Upgrade: Integrating a Liquid snippet and new JavaScript functions to display active codes in the cart summary.
-
The Logic: Creating a function that renders the applied codes (read from the cookie/cart data) and attaching event listeners to a small "X" icon next to each code. Clicking the "X" triggers a cart update to remove that specific code.
-
The Goal: Improve trust and customer experience by providing transparency over automated discounts and full control over their order totals.
3. 🎁 Required Product Auto-Inclusion
This system ensures that if a customer uses a promotional link that requires a specific product to be in the cart for the discount to work (e.g., "Buy Product A to get 20% off"), the required product is automatically added.
-
The Upgrade: Defining a mapping in the JS where Discount Code X is linked to Required Product Y ({ code: 'BOGO', requires: 'HANDLE' }).
-
The Logic: Before applying the discount, the JavaScript checks the cart for the required product handle. If it's missing, the script automatically adds it using the /cart/add.js endpoint, then applies the associated discount code.
-
The Goal: Eliminate the user error where a customer clicks a discount link but fails to qualify because they forgot to add the qualifying item, guaranteeing successful promotion use and boosting the required item's sales.
👉 Ready to automate your conversion campaigns and prevent checkout errors? Let me know which advanced feature you'd like to implement, and we can discuss a custom setup plan.