Offering a dynamic Free Shipping Progress Bar is one of the most effective methods to increase Average Order Value (AOV) on Shopify. By visually illustrating how close a shopper is to unlocking complimentary delivery (e.g. "Add $14.00 more to unlock Free Shipping!"), merchants incentivize adding complementary items before checkout. Below is a complete Liquid and JavaScript implementation guide for Shopify Dawn and Online Store 2.0 themes.
β‘ Engineering Requirements: Server Liquid + Client Ajax Synchronization
A resilient progress bar requires two distinct synchronization layers: (1) Liquid arithmetic that computes the remaining deficit and percentage progress on initial page load, and (2) JavaScript event hooks that dynamically update the progress bar width and message when shoppers modify cart quantities in Ajax drawers without triggering full page reloads.
1. Production Liquid Snippet: snippets/free-shipping-bar.liquid
Create a new snippet under Snippets β Add a new snippet named free-shipping-bar.liquid and insert the following code:
{% comment %}
snippets/free-shipping-bar.liquid
Configurable Free Shipping Threshold in Cents (e.g., $75.00 = 7500 cents)
{% endcomment %}
{% assign threshold = 7500 %}
{% assign current_total = cart.total_price %}
{% assign remaining = threshold | minus: current_total %}
{% if current_total >= threshold %}
{% assign progress_percent = 100 %}
{% else %}
{% assign progress_percent = current_total | times: 100.0 | divided_by: threshold | round %}
{% endif %}
<div id="free-shipping-bar" class="shipping-bar-container" data-threshold="{{ threshold }}">
<p class="shipping-bar-message">
{% if current_total >= threshold %}
<span class="unlocked">π Congratulations! You have unlocked <strong>FREE Shipping</strong>!</span>
{% else %}
Add <strong class="remaining-amount">{{ remaining | money }}</strong> more to unlock <strong>FREE Shipping</strong>!
{% endif %}
</p>
<div class="shipping-bar-track">
<div class="shipping-bar-progress" style="width: {{ progress_percent }}%;"></div>
</div>
</div>
2. Styling the Bar: assets/base.css
Add this performant, hardware-accelerated CSS to the bottom of assets/base.css:
.shipping-bar-container {
padding: 12px 16px;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
margin: 12px 0;
text-align: center;
}
.shipping-bar-message {
font-size: 13px;
color: #e5e7eb;
margin-bottom: 8px;
}
.shipping-bar-track {
width: 100%;
height: 8px;
background: rgba(255, 255, 255, 0.15);
border-radius: 999px;
overflow: hidden;
}
.shipping-bar-progress {
height: 100%;
background: linear-gradient(90deg, #ff6b35, #10b981);
border-radius: 999px;
transition: width 0.35s ease-in-out;
}
3. Ajax Cart Drawer Hook: assets/cart-drawer.js
To update the progress bar without reloading the page, attach a JavaScript listener to cart mutation events. In Dawn's cart-drawer.js, update the render cycle:
// Update shipping progress bar when cart state changes
function updateShippingBar(cart) {
const bar = document.getElementById('free-shipping-bar');
if (!bar) return;
const threshold = parseInt(bar.dataset.threshold, 10);
const currentTotal = cart.total_price;
const remaining = threshold - currentTotal;
const progressEl = bar.querySelector('.shipping-bar-progress');
const messageEl = bar.querySelector('.shipping-bar-message');
if (currentTotal >= threshold) {
progressEl.style.width = '100%';
messageEl.innerHTML = '<span class="unlocked">π Congratulations! You have unlocked <strong>FREE Shipping</strong>!</span>';
} else {
const percent = Math.min(100, Math.round((currentTotal / threshold) * 100));
progressEl.style.width = percent + '%';
const formattedRemaining = '$' + (remaining / 100).toFixed(2);
messageEl.innerHTML = 'Add <strong class="remaining-amount">' + formattedRemaining + '</strong> more to unlock <strong>FREE Shipping</strong>!';
}
}
4. Shopify Markets & Multi-Currency Considerations
If your store operates in multiple countries via Shopify Markets, a hardcoded $75.00 threshold will produce inaccurate targets in GBP, EUR, or JPY. To support currency localization:
- Store market thresholds in Shopify Metafields or theme settings keyed to
localization.country.currency.iso_code. - Use Shopify's native
| moneyfilter so currency symbols and regional decimal conventions match the shopper's active locale.
5. Multi-Tier Progression: Free Shipping to Free Gift Stacking
High-growth brands often stack rewards to push Average Order Value even higher. For example: Tier 1 ($50) unlocks Free Standard Shipping, while Tier 2 ($100) unlocks a Free Full-Size Mystery Gift. In Liquid, you can chain these milestones using conditional branching:
{% assign tier_1 = 5000 %}{% comment %} $50 Free Shipping {% endcomment %}
{% assign tier_2 = 10000 %}{% comment %} $100 Free Gift {% endcomment %}
{% if cart.total_price < tier_1 %}
{% assign diff = tier_1 | minus: cart.total_price %}
Add {{ diff | money }} for <strong>Free Shipping</strong>!
{% elsif cart.total_price >= tier_1 and cart.total_price < tier_2 %}
{% assign diff = tier_2 | minus: cart.total_price %}
You unlocked Free Shipping! Add {{ diff | money }} to unlock a <strong>Free Gift</strong>! π
{% else %}
π All Rewards Unlocked! Free Shipping + Free Gift included!
{% endif %}
6. Frequently Asked Questions
Collection quick-add forms often use separate Ajax fetch requests that bypass the cart drawer's listener. To fix this, ensure your theme emits a custom JavaScript event (such as document.dispatchEvent(new CustomEvent('cart:updated', { detail: { cart } }))) inside your global Ajax add-to-cart handler, and listen to that event inside your shipping bar script.
No. Unlike third-party apps that load external React runtimes and analytics trackers over network connections, this pure Liquid and vanilla JavaScript implementation weighs under 2KB, executes in under 1 millisecond, and creates zero layout shift (CLS) because its dimensions are reserved in CSS.
π Verified Documentation & References:
Optimize Your Cart Drawer Architecture
Want to implement native tier incentives, slide-out upsells, and free gift thresholds without monthly app fees? Review our Shopify Development services or explore our App-Free Cart Drawer Engineering Guide.