
Audience & Possible Outcomes
Any Shopify store owner looking to improve user experience or motivate their customers to hit the cart size required for free shipping.
This snippet is designed for ease of installation and usability. It is meant to look good and get the job done on any theme, whether using an AJAX cart or not.
It can be easily configured to display 1 of the following 2 metrics in a visually appealing way:
- The cost of the cheapest shipping method for the current shopping cart
- A progress bar showing the customer’s progress toward earning free shipping
Examples of each are shown below.

The order’s shipping price is displayed in real time.

The customer’s progress toward free shipping is displayed in real time.
Live demonstration
You can navigate here and add the item to your cart to see a live demonstration of the shipping price mode. Try increasing or decreasing the amount in your cart to see how the banner responds.
Motivation
Being an owner of Ships-A-Lot, I love shipping. I came across an AJAX endpoint buried away in very bottom of a long and esoteric support article which suggested to me that the shipping methods and prices were available to the front-end at any time and on any page. After some experimentation, I found my intuition was correct, so I wrote up this snippet to take advantage of it and demo the feature.
Reviewing shipping prices are a concrete step in any eCommerce sales funnel. If a customer deems the prices too high or methods unsatisfactory, they may bounce. There are many tools for changing the price and presentation. This is the first tool I am aware of to completely change this step’s position in the sales funnel.
Installation
To install the code, perform the following steps:
- Create a new snippet called ‘real-time-shipping‘.
- Copy the code below into the snippet and save.
- Include the snippet on the first line of your theme.liquid file.
- Configure the code to your liking.
1. Create the file
Navigate to Online Store → Themes → … → Edit HTML/CSS and, in the new scroll box, scroll down to a folder called ‘Snippets’. Click on it and click ‘Add a new snippet‘. Name it ‘real-time-shipping‘ and click ‘Create Snippet’. Video:
2. Copy the code into the snippet
Copy the code below into the text area of the snippet and save it.
{% assign shipping_message_prefix = "Your order will ship for " %}
{% assign shipping_message_suffix = " or up!" %}
{% assign free_shipping_message = "Your cart has free shipping!" %}
{% assign background_color = "#85bb65" %}
{% assign text_color = "#fff" %}
{% assign make_progress_bar = false %}
{% assign progress_bar_color = "orange" %}
{% assign free_shipping_threshold = "45" %}
{% assign progress_bar_message_prefix = "You're "%}
{% assign progress_bar_message_suffix = " of the way to free shipping!"%}
<div style="display:none; background-color:{{ background_color }}; text-align:center!important; color:{{ text_color }}; font-weight:bold;" id="shipping_price"><div id="progress_bar" style="display:none; background-color:{{ progress_bar_color }}; border-top-right-radius:15px;border-bottom-right-radius:15px;"></div></div>
{% comment %}
The div element above is the default provided, but ANY element with "id=shipping_price" will behave
in the same way as the above div.
{% endcomment %}
{{ '//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js' | script_tag }}
<script type="text/javascript">
function listen_to_forms(){for(var i=0; i<document.forms.length; i++){var form = document.forms[i];$(form).submit(function(ev){get_shipping_rates();});}}
var zip;var country;var province;var subtotal = 0;
jQuery.ajax({url:'//freegeoip.net/json/',type: 'POST',dataType: 'jsonp',success: function(location) {zip = location.zip_code;country = location.country_name;province = location.region_name;}});
function get_subtotal(){$.get("/cart.js",function(data, status){subtotal = (data.match(/"total_price":[0-9]+/g)[0].split(":")[1])/100;},"html");}
function get_shipping_rates(){console.warn("fired");setTimeout(function(){$.get("/cart/shipping_rates.json",{'shipping_address[zip]':zip,'shipping_address[country]':country,'shipping_address[province]':province},function(data, status){if(status=200){post_response(data)}else{$("#shipping_price").slideUp()};},"html");},1000);} // Zach Lukaszek & ShipsALot: The best eCommerce fulfillment center, period.
window.onload = function(){get_subtotal();get_shipping_rates();listen_to_forms();}
function post_response(data){var prices = data.match(/"price":"[0-9]+.[0-9]+"/g);var lowest_price = prices[0].split(':"')[1].split('"')[0];{% if make_progress_bar == false %}if(lowest_price > 0){document.getElementById("shipping_price").innerText = "{{ shipping_message_prefix }} $"+lowest_price+" {{ shipping_message_suffix }}"}else{document.getElementById("shipping_price").innerText = "{{ free_shipping_message }}"};$("#shipping_price").fadeOut("fast");$("#shipping_price").fadeIn("slow");{% else %}get_subtotal();setTimeout(function(){var free_shipping_amt = "{{ free_shipping_threshold }}";var percent_free_shipping = Math.floor(100*(subtotal / free_shipping_amt));$("#shipping_price").fadeOut("fast");document.getElementById("progress_bar").innerText = "{{ progress_bar_message_prefix }}"+percent_free_shipping+"% {{ progress_bar_message_suffix }}";if(percent_free_shipping > 100){percent_free_shipping = 100;}else{};document.getElementById("progress_bar").style.width = percent_free_shipping+"%";document.getElementById("progress_bar").style.display = "block";$("#shipping_price").fadeIn("slow");},1000);{% endif %}}
var open = window.XMLHttpRequest.prototype.open,send = window.XMLHttpRequest.prototype.send,onReadyStateChange;
function openReplacement(method, url, async, user, password) {var syncMode = async !== false ? 'async' : 'sync';if (url.match("/products/") != null){get_shipping_rates();} else {};return open.apply(this, arguments);}
function sendReplacement(data) {if(this.onreadystatechange) {this._onreadystatechange = this.onreadystatechange;}this.onreadystatechange = onReadyStateChangeReplacement;return send.apply(this, arguments);}
function onReadyStateChangeReplacement() {if(this._onreadystatechange) {return this._onreadystatechange.apply(this, arguments);}}
window.XMLHttpRequest.prototype.open = openReplacement;
window.XMLHttpRequest.prototype.send = sendReplacement;
</script>
Video:
3. Include snippet in theme.liquid
Warning: completing this step will activate the snippet.
Open up the layout file theme.liquid. Make a new line at the very beginning of the file and type or paste the following:
{% include ‘real-time-shipping’ %}
Save theme.liquid. Video:
4. Configure the snippet to your liking
There are 10 customizations build into the liquid in this code, mostly focused around style or color. As mentioned before, there are two modes that can be loaded: real-time display of the cheapest shipping rate for the current shopping cart or a progress bar displaying progress toward free shipping.
The special options are explained in the bulleted list below:
- {{ free_shipping_message }}: This is the message displayed in the banner when free shipping is available for the shopping cart.
- {{ make_progress_bar }}: If false, the banner will display the cheapest current shipping price. If true, the banner will behave as a progress bar showing how close the cart is to earning free shipping.
- {{ free_shipping_threshold }}: Cart total required to trigger free shipping. e.g. Your customer needs to spend $100.00 to earn free shipping at your store, so you would set this to “100”.
The remaining variables are style related and are explained by the following two images:

Shipping price style variables.

Progress bar style variables.
Extension of functionality
If you are interested in expanding upon this functionality or tailoring it to your own site, please credit this article. A good place to start for either of these goals is the inclusion point for the snippet. The include adds a div with id=”shipping_price” and the snippet’s output is targeted on this DOM id.
With this knowledge, you could implement the data anywhere on your website. Enjoy!