How to Add a Countdown Timer to Shopify Without an App

2026-09-13 · upselling

Countdown timers are one of the highest-leverage conversion elements you can add to a Shopify store, and you don't need to pay $10–$20/month for an app to get one. With about 30 lines of Liquid, CSS, and JavaScript, you can build a timer that lives inside your theme, loads instantly, and doesn't add another script to your storefront's performance budget. This guide walks through the whole build for a modern Shopify theme (Dawn, Refresh, Craft, or any Online Store 2.0 theme).

Why Use a Countdown Timer for Flash Sales (Without an App)

Urgency moves buyers. A visible timer that says "this offer ends in 2 hours" does three things at once: it gives shoppers a reason to decide now rather than later, it frames a discount as temporary rather than permanent, and it reduces the "I'll come back to this" problem that quietly kills e-commerce conversion.

App-based timers work fine, but they carry real costs:

A custom snippet gives you full control over markup, styling, and behavior, adds almost no weight to the page, and costs nothing per month.

What You'll Need Before You Start

You need three things:

One important limitation to understand up front: this timer runs in the shopper's browser, so it uses the visitor's local clock. That's fine for most flash sales. If you need a timer that's identical for every visitor regardless of their device clock or timezone, you'll need a server-side source for the end time — for example, a metafield you update manually, or a small app proxy. For most stores, a fixed end date in your theme settings is accurate enough.

Step 1: Create a New Snippet for the Timer Code

Snippets are reusable Liquid partials. Keeping the timer in a snippet means you can drop it onto a product page, a landing page, or a collection template without duplicating code.

  1. In Edit code, scroll to the Snippets folder.
  2. Click Add a new snippet and name it countdown-timer.
  3. Paste the following into the file:
{%- assign end_time = settings.countdown_end_time | default: '2025-12-31T23:59:59' -%}
<div class="countdown-timer" data-end="{{ end_time }}">
  <span class="countdown-timer__label">{{ settings.countdown_label | default: 'Offer ends in' }}</span>
  <span class="countdown-timer__clock" aria-live="polite">
    <span data-unit="days">00</span>d
    <span data-unit="hours">00</span>h
    <span data-unit="minutes">00</span>m
    <span data-unit="seconds">00</span>s
  </span>
</div>

The data-end attribute is what your JavaScript will read. The aria-live="polite" attribute tells screen readers to announce updates without interrupting whatever the shopper is doing.

Save the snippet. It won't appear anywhere yet — that's expected.

Step 2: Add the Countdown Timer to Your Product Template

Now render the snippet where you want the timer to appear. The most common placement is directly under the product title or above the Add to Cart button, because that's where the purchase decision happens.

Open Sections → main-product.liquid (in Dawn and most OS 2.0 themes) and find the block that renders the product title. Add this line immediately after it:

{% render 'countdown-timer' %}

If you want the timer on every product rather than just one, that's it — you're done. If you want it on a single product only, wrap it in a conditional:

{% if product.handle == 'summer-bundle' %}
  {% render 'countdown-timer' %}
{% endif %}

Replace summer-bundle with your actual product handle (the last part of the product URL). You can also render the snippet inside a custom Liquid block on any section if you'd rather not touch section code — add a Custom Liquid block in the theme editor and paste the render tag inside it.

Step 3: Style the Timer to Match Your Theme

Add styles at the bottom of Assets → base.css (or your theme's main stylesheet). Adjust the colors to match your brand:

.countdown-timer {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-radius: 6px;
  background: #111;
  color: #fff;
  font-size: 0.95rem;
  font-weight: 600;
  margin: 1rem 0;
}

.countdown-timer__clock span[data-unit] {
  font-variant-numeric: tabular-nums;
  min-width: 2ch;
  display: inline-block;
  text-align: center;
}

.countdown-timer--expired {
  display: none;
}

Two details matter more than the rest. First, font-variant-numeric: tabular-nums keeps the digits from shifting width as they change, which prevents the whole timer from jittering every second. Second, min-width: 2ch reserves space so a "9" doesn't collapse the layout when it rolls to "10."

If your theme uses CSS variables for colors, swap the hex values for those variables so the timer inherits your palette automatically.

Step 4: Set the Timer to End at a Specific Time

You have two options for setting the end time, and the right one depends on how often you run promotions.

Approach Best for How to change it Trade-off
Hardcoded in the snippet One-off, permanent campaigns Edit the snippet directly Requires a code edit each time
Theme setting Frequent, non-technical updates Theme editor → Theme settings Requires adding a settings schema entry

For the theme setting route, open Config → settings_schema.json and add a text field:

{
  "type": "text",
  "id": "countdown_end_time",
  "label": "Countdown end time (ISO 8601)",
  "default": "2025-12-31T23:59:59"
}

Use ISO 8601 format — 2026-01-15T18:00:00 — because JavaScript's Date parser handles it consistently across browsers. Then add the JavaScript that drives the clock, either in the snippet or in a separate asset file:

document.querySelectorAll('.countdown-timer').forEach(function (el) {
  var end = new Date(el.dataset.end).getTime();
  var clock = el.querySelector('.countdown-timer__clock');

  function tick() {
    var diff = end - Date.now();
    if (diff <= 0) {
      el.classList.add('countdown-timer--expired');
      clearInterval(timer);
      return;
    }
    var d = Math.floor(diff / 86400000);
    var h = Math.floor((diff % 86400000) / 3600000);
    var m = Math.floor((diff % 3600000) / 60000);
    var s = Math.floor((diff % 60000) / 1000);
    clock.querySelector('[data-unit="days"]').textContent = String(d).padStart(2, '0');
    clock.querySelector('[data-unit="hours"]').textContent = String(h).padStart(2, '0');
    clock.querySelector('[data-unit="minutes"]').textContent = String(m).padStart(2, '0');
    clock.querySelector('[data-unit="seconds"]').textContent = String(s).padStart(2, '0');
  }

  tick();
  var timer = setInterval(tick, 1000);
});

If the end time is in the past, the timer hides itself automatically instead of showing negative numbers — which is what you want, since a timer stuck at zero looks broken.

Step 5: Test and Troubleshoot Your Countdown Timer

Preview your theme before publishing, then work through this checklist:

Also test on mobile. Timers that look fine on desktop often overflow narrow product pages, especially when they include a long label like "Flash sale ends in."

Conclusion

Building a countdown timer into your Shopify theme takes about 30 minutes and removes a recurring app subscription from your stack. You keep full control over styling, you avoid the performance cost of third-party scripts, and you can drop the same snippet onto any template. Start with a hardcoded end date on one product, confirm it converts, then move the setting into your theme editor so you can run promotions without touching code.

FAQ

Can I add a countdown timer to Shopify without any coding at all? Not without an app. Shopify's theme editor doesn't include a native countdown block, so the no-app route always involves editing your theme's Liquid, CSS, or JavaScript. The snippet approach above is the lowest-code version of that.

Will a countdown timer slow down my store? Not meaningfully. The snippet adds a few hundred bytes of HTML and roughly 20 lines of JavaScript, which is far less than a typical countdown app that loads its own framework and stylesheet. The main performance consideration is placing the script so it doesn't block rendering.

Does the timer reset for each visitor? No. It counts down to a fixed date and time you specify, so every visitor sees the same deadline based on their own device clock. If a shopper's device clock is wrong, their timer will be wrong too — which is why server-sourced end times are worth considering for high-stakes promotions.