Adding a countdown timer in Shopify is one of the most effective ways to create urgency and boost conversions. While many store owners rely on apps, it’s possible to add a timer without installing any third-party applications. This guide will show you a simple, step-by-step method to integrate a countdown timer in your Shopify store for free.
Why Use a Countdown Timer in Your Shopify Store?
A countdown timer adds urgency and encourages customers to complete their purchases quickly. It can be particularly effective during sales, promotions, or limited-time offers. By highlighting scarcity, you create FOMO (Fear of Missing Out), which often results in higher conversion rates. Moreover, a countdown timer can improve the overall shopping experience by clearly communicating deadlines and special deals.
Step 1: Access Your Shopify Theme Code
- Log in to your Shopify admin panel.
- Go to Online Store > Themes.
- Click Actions > Edit Code on your current theme.
Step 2: Add Countdown Timer HTML
Locate the section where you want your timer to appear (for example, product pages or homepage). Add the following HTML code snippet:
<div id="countdown-timer"> Sale ends in: <span id="timer"></span> </div>
{% comment %}
Liquid Variables
{% endcomment %}
{% liquid
assign timer_section_title = section.settings.timer_section_title
assign timer_section_subtitle = section.settings.timer_section_subtitle
assign date_picker_time = section.settings.date_picker
assign cta_bg_color = section.settings.cta_bg_color
assign cta_text_color = section.settings.cta_text_color
assign title_text_color = section.settings.title_text_color
assign subtitle_text_color = section.settings.subtitle_text_color
assign subtitle_font_weight = section.settings.subtitle_font_weight
assign section_bg_color = section.settings.bg_color
assign timer_color = section.settings.timer_color
%}
{% comment %}
Custom CSS Styles
{% endcomment %}
{% style %}
.timer-flex-container{
background: {{ section_bg_color }};
align-items: center;
justify-content: center;
column-gap: 20px;
padding: 10px;
display: flex;
opacity: 1;
transition: 0.5s all linear;
}
.hide-element{
padding: 0 !important;
opacity: 0;
}
.timer-flex-container .timer {
display: flex;
justify-content: space-around;
}
.timer-flex-container .timer-subtitle{
text-align:center; margin: 5px 0;
}
.timer-flex-container .timer-subtitle{
color: {{ subtitle_text_color }};
font-weight: {{ subtitle_font_weight }};
font-family: inherit;
font-size: 18px;
}
.timer-flex-container .timer--expired {
display: none;
}
.timer-flex-container .timer__title {
text-align: center;
font-weight: bold;
}
.timer-flex-container .timer-display {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: center;
margin-top: 5px;
}
.timer-flex-container .timer{
margin-right: 1rem;
}
.timer-flex-container .timer-block {
position: relative;
padding: 0 10px;
}
.timer-flex-container .timer-block__num,
.timer-flex-container .timer-block__unit {
display: block;
text-align: center;
color: {{ timer_color }};
font-family: inherit;
}
.timer-flex-container .timer-block__num{
font-size: 16px;
}
.timer-flex-container .timer-block__unit{
font-size: 13px;
margin-top: -7px;
}
.timer-flex-container .colon {
font-size: 16px;
color: {{ timer_color }};
}
.timer-flex-container .timer-button{
max-height: 45px;
background-color: {{ section.settings.cta_bg_color }} !important;
color: {{ section.settings.cta_text_color }} !important;
border-radius: 4px;
}
.timer-flex-container .timer-button::after{
content: none;
}
.timer-display-flex{
display: flex;
align-items: center;
}
.gradient-bg-animation{background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 400% 400%;
animation: gradient 15s ease infinite;}
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@media screen and (max-width: 768px){
.timer-flex-container{
flex-direction: column;
}
}
@media screen and (max-width: 391px){
.timer-display-flex{
width: 100%;
justify-content: space-evenly;
flex-wrap: wrap;
}
}
{% endstyle %}
{% unless date_picker_time == blank %}
<div class="timer-flex-container hide-element gradient-bg-animation">
{% unless timer_section_title == blank %}
<div class="timer-subtitle">{{ timer_section_title }}</div>
{% endunless %}
<div class = "timer-display-flex">
<countdown-timer-bar schema-time="{{ date_picker_time }}">
<div class="timer" style="visibility: hidden;">
<div class="timer-display">
<div class="timer-block">
<span class="timer-block__num js-timer-days">00</span>
<span class="timer-block__unit">Days</span>
</div>
<div class="colon">:</div>
<div class="timer-block">
<span class="timer-block__num js-timer-hours">00</span>
<span class="timer-block__unit">Hrs</span>
</div>
<div class="colon">:</div>
<div class="timer-block">
<span class="timer-block__num js-timer-minutes">00</span>
<span class="timer-block__unit">Mins</span>
</div>
<div class="colon">:</div>
<div class="timer-block">
<span class="timer-block__num js-timer-seconds">00</span>
<span class="timer-block__unit">Secs</span>
</div>
</div>
</div>
</countdown-timer-bar>
{% unless section.settings.timer_section_btn_link == blank and timer_section_btn_text == blank %}
<a class="timer-button button" href="{{ section.settings.timer_section_btn_link }}">
<span>{{
section.settings.timer_section_btn_text }}
</span>
</a>
{% endunless %}
</div>
</div>
{% endunless %}
{% comment %}
Native Web Component Definition
{% endcomment %}
{% javascript %}
class CountdownTimerBar extends HTMLElement {
constructor() {
super();
}
init() {
this.schemaTime = this.getAttribute('schema-time');
this.timer = this.querySelector(".timer")
this.countdown = new Date(this.schemaTime).getTime();
this.second = 1000;
this.minute = this.second * 60;
this.hour = this.minute * 60;
this.day = this.hour * 24;
this.timerInterval = null;
this.startTimer();
setTimeout(() => this.timer.style.visibility = "visible", 1000)
}
padWithLeadingZero = (number) => {
if (number < 10) {
return '0' + number;
} else {
return number;
}
};
isDateInPast(date) {
const now = new Date();
return date < now;
}
startTimer() {
//Have quick check to see if Date input in the countdown class variable is in the past
//Helper function
const timerElem = this.timer
this.timerInterval = setInterval(() => {
const now = new Date().getTime();
const distance = this.countdown - now;
const dayCalc = Math.floor(distance / this.day);
const hourCalc = Math.floor((distance % this.day) / this.hour);
const minuteCalc = Math.floor((distance % this.hour) / this.minute);
const secondCalc = Math.floor((distance % this.minute) / this.second);
timerElem.querySelector('.js-timer-days').textContent = this.padWithLeadingZero(dayCalc);
timerElem.querySelector('.js-timer-hours').textContent = this.padWithLeadingZero(hourCalc);
timerElem.querySelector('.js-timer-minutes').textContent = this.padWithLeadingZero(minuteCalc);
timerElem.querySelector('.js-timer-seconds').textContent = this.padWithLeadingZero(secondCalc);
}, this.second);
}
disconnectedCallback() {
clearInterval(this.timerInterval);
}
connectedCallback(){
this.init();
console.log("countdown timer was added to the page")
const timerFlexContainer = window.document.querySelector(".timer-flex-container")
const timerElem = this.timer
const pastDate = this.isDateInPast(this.countdown)
if(pastDate){
timerFlexContainer.remove()
this.remove()
}
window.setTimeout(() => {
timerFlexContainer.classList.remove("hide-element")
}, 2000);
}
disconnectedCallback(){
console.log("The Timer date has passed so the timer was removed")
}
}
customElements.define('countdown-timer-bar', CountdownTimerBar);
{% endjavascript %}
{% comment %}
Section Customization Options
{% endcomment %}
{% schema %}
{
"name": "Countdown Top Bar",
"tag": "section",
"enabled_on": {
"groups": ["header"]
},
"settings": [
{
"type": "header",
"content": "General Section Settings"
},
{
"type": "color",
"id": "bg_color",
"default": "#fff",
"label": "Section Background Color"
},
{
"type": "header",
"content": "Title Settings"
},
{
"type": "text",
"id": "timer_section_title",
"label": "Section Title",
"default": "Hurry up! Sale ends in:"
},
{
"type": "color",
"id": "subtitle_text_color",
"default": "#fff",
"label": "Section Title Text Color"
},
{
"type": "select",
"id": "subtitle_font_weight",
"default": "500",
"label": "Normal or Bolded Text",
"options": [
{
"label": "Normal",
"value": "500"
},
{
"label": "Bold",
"value": "700"
}
]
},
{
"type": "header",
"content": "Timer Settings"
},
{
"type": "text",
"id": "date_picker",
"label": "Choose a date",
"info": "Input date in this format: 07/21/2023. When date is in past section will disappear"
},
{
"type": "color",
"id": "timer_color",
"default": "#fff",
"label": "Timer Color"
},
{
"type": "header",
"content": "Button Settings"
},
{
"type": "url",
"id": "timer_section_btn_link",
"label": "Call to Action Button Link"
},
{
"type": "text",
"id": "timer_section_btn_text",
"label": "Call to Action Button Text",
"default": "Shop Now!"
},
{
"type": "color",
"id": "cta_bg_color",
"default": "#4770db",
"label": "Call to Action Background Color"
},
{
"type": "color",
"id": "cta_text_color",
"default": "#fff",
"label": "Call to Action Text Color"
}
],
"presets": [
{
"name": "Countdown Top Bar"
}
]
}
{% endschema %}