How to add a "x until free delivery" gauge [E-commerce]

tldr : The point of this tutorial is to explain how you can add a “gauge” to your webflow e-commerce in order to achieve things like the Glossier shopping cart’s x€ left before free shipping (https://www.glossier.com/)

I’ve been playing around with webflow e-commerce for a year now… and even it if still has limitations, it still is super nice to be able to style everything the way you want and easily build functionnality when you need it. Many clients we have at Pepperclip ask us to build some little extra features on top of what webflow can do natively… I’ll try to share here one of these features. I’m not a native english speaker so I hope there won’t be to many mistakes :sweat_smile:

Here we go :

In order to have a gauge working you need :
— A threshold value until something happens
— Be able to listen to what is happening in the cart (how many items or what the total is) all the time

The concept :
By comparing the cart’s content with the threshold you get a value which you can then translate into a percentage value which will be the width of a coloured bar (a div with a background color that you can style in webflow).

The result in action : https://6pack-ecom.webflow.io/
With a threshold of 6 cans to make a 6-pack and 12€ to get free shipping

First of all :
— You need to create you “free delivery” or whatever messages in webflow as well as your gauge “bars” and give all of those their own class. Don’t forget that you need to wrap with a span the compared value that you show the user in order to be able to target it and update it with the correct value each time the shopping cart’s content changes.

And that’s the tricky part is being able to listen to the shopping cart changes since it seems Webflow’s e-commerce cart content is stored in a server side cookie for each user session (that’s why when switching pages or modifying your order, there is a tiny lag in the update of the cart).

For those who understand jquery and javascript this is pretty straightforward, but for the others, let me explain :
In order to do that you can use a Mutation Observer (MutationObserver - Web APIs | MDN). Basically what it does is enable you to look at changes in the DOM Tree for specific elements and do something about it :slight_smile: . This means, each time something changes in the cart the mutation observer will know the user has made a change in his shopping cart, whatever the change (add, delete product, change qty…).
Once this is setup you just have to fetch the cart qty value or the cart’s subtotal to compare it with your threshold.

So here’s the code for a quantity Gauge :

<!-- START PRODUCT COUNTER GAUGE || BY PEPPERCLIP STUDIO -->
<script>
// Initialize texts
$(".cans-info").hide();
$(".cans-info-alt").hide();
$(".checkout-abs").hide();
// select the target node — here : .cart-list
var target = document.getElementById('target');
// input here your reference value
var targetQty = 6;
// create an observer instance
var observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
		//console.log('cart update');  
        setTimeout(function(){     
        var currentQty = $('.w-commerce-commercecartopenlinkcount').text();
        var leftQty = targetQty - currentQty ;
        // update counter — console.log('cans missing' + ' ' + leftQty);
            if ( leftQty <= 0 ) {
            		$(".cans-left").text(leftQty);
                $(".cans-info").hide();
                $(".cans-info-alt").show();
                $(".checkout-abs").show();
            }
            else {
            		$(".cans-info-alt").hide();
                $(".checkout-abs").hide();
            		$(".cans-info").show();
                $(".cans-left").text(leftQty);   
            }
        // update progression stackbar — console.log(progressBar);
        var progressBar = currentQty / targetQty * 100;
        $(".completed-bar").css('width', progressBar + '%');       
    }, 300);
    });
});
// configuration of the observer:
var config = {
    attributes: false,
    childList: true,
    characterData: false
};
// pass in the target node, as well as the observer options
observer.observe(target, config);
</script>
<!-- END PRODUCT COUNTER GAUGE || CHEERS --> 

I’ve tried to comment as much as possible the code so that everyone can understand what it does.
But here’s the english version :sweat_smile:

1 / Hide the messages that need to be hidden when the page loads
2 / Target the shopping cart’s content div (the one that contains each product item, usually the cart’s collection list)
3 / Tell your script what your threshold value is
4 / Setup your mutation observer
5 / Set a delay (because the cart update has a small lag)
6 / Get the current cart qty value
7 / Compare it to the threshold
8 / If negative, update the result value and hide the countdown messages to show the success message
9 / If positive, hide the success messages and show the countdown messages with the updated result value
10 / Once this is done, update the coloured progress bar to show where the user stands
11 / Wrap everything up and tell the script to start observing

Here’s how to do the same with a subtotal gauge :

<!-- START PRICE TO DELIVERY GAUGE || BY PEPPERCLIP STUDIO -->
<script>
// initialize texts
$(".free-delivery-info").hide();
// select the target node — here : .cart-list
var target = document.getElementById('target');
// input here your reference value
var targetPrice = 12;
// create an observer instance
var observer2 = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
		//console.log('cart update');  
        setTimeout(function(){     
        var currentPrice = $('.w-commerce-commercecartordervalue').text().replace(/[^\d.]/g, '');
        var leftPrice = targetPrice - currentPrice ;
        if ( leftPrice <= 0 ) {
                $(".delivery-info").hide();
                $(".free-delivery-info").show();
            }
            else {
            		$(".delivery-info").show();
                $(".free-delivery-info").hide();
            }
        $(".price-left").text(leftPrice);
        // update progression stackbar — console.log(progressBar);
        var progressBar2 = currentPrice / targetPrice * 100;
        $(".completed-bar-alt").css('width', progressBar2 + '%');       
    }, 300);
    });
});
// configuration of the observer:
var config = {
    attributes: false,
    childList: true,
    characterData: false
};
// pass in the target node, as well as the observer options
observer2.observe(target, config);
</script>
<!-- END PRICE TO DELIVERY GAUGE || CHEERS -->

Everything works the same way here. You can add the value update as for the other code and hide / show as many messages as you want.

I hope this will help those of you who were wondering how to achieve stuff like this with Webflow e-commerce.
@Waldo , @PixelGeek , @webdev, @sabanna if you’ve heard about some users looking for a similar thing…

And I hope everyone stays safe from Covid-19.

Cheers to all

7 Likes

Works like a charm!
Thank you for the detailed tutorial :relaxed:

1 Like

Hi Dorian, thank you for your post.
I have very carefully edited the code but it doesn’t work unfortunately.

I took the second code for a free shipping progress bar.

i deleted some parts like the ‘hide’ function because i do it with the native condition functions in webflow.
Then i changed the targeted classes to ID’s ONLY, because i will convert the theme to shopify via udesly.

I also renamed the variables to make it more clear for myself.

Here is the code:

<script>
// create a variable with the name 'target', and get the .cart-body-section's content id: 'cart-body-section'
var target = document.getElementById('cart-body-section');
// create a variable with the name 'shippingThreshold', and set the shipping threshold to 40
var shippingThreshold = 40;
// create an observer instance with the variable name 'observer2'
var observer2 = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
		// set delay timeout function, due to delay of cart update
        setTimeout(function(){
        // create a variable with the name 'subTotal', take the .cart-subtotal's text value, and replace it  with /[^\d.]/g, ''
        var subTotal = $('cart-subtotal').text().replace(/[^\d.]/g, '');
        // create a variable with the name 'shippingdifference', which equals 'subTotal' variable minus (-) 'shippingThreshold' variable...
        var shippingdifference = subTotal - shippingThreshold;
            }
        // ...get the display text block id, and replace the text with the updated value from the created variable 'shippingdifference'
        $('cart-shipping-difference').text(shippingdifference);
        // create a variable with the name 'progressBar'
        var progressBar = subTotal / shippingThreshold * 100;
        $('cart-shipping-meter-fill').css('width', progressBar + '%');
    }, 300);
    });
});
// configuration variable of the observer:
var config = {
    attributes: false,
    childList: true,
    characterData: false
};
// pass in the target node, as well as the observer options
observer2.observe(target, config);
</script>

Can you check what i did wrong?

Again thank you for the great insights with your post. Learned a lot already.

Dom

Does this still work? Would love to try…