How to Add a Countdown Timer to Shopify
Two lines pasted into a Custom Liquid section, and your product page has a deadline on it.
Every theme in the Shopify Theme Store is required to ship a Custom Liquid section, and that one requirement is why a countdown on a Shopify product page never touches a code file. The section is a field in the theme editor that takes raw HTML, so a loader script and one mount element go into the product template the way you would drop in a rich text block, with the file tree left closed. What the clock counts toward is the part worth deciding slowly. The BootSignal countdown runs to a fixed timestamp you write into data-target, the same instant for every shopper, so it cannot be turned into the evergreen timer that quietly restarts for each visitor. Plans matter only at the edges: Shopify documents no plan requirement for the theme editor or for that section, and the four plans that cannot do this are the ones with no ordinary storefront to put a section on.
No upgrade to buy, and the four plans that sit outside that
Shopify documents the theme code editor, the theme editor and the Custom Liquid section without naming a plan requirement, and the Basic plan page says Basic includes an online store you customize "through Shopify's built-in theme editor". So on Basic and up there is nothing to buy. Four of the nine current plans fall outside that reading, for two different reasons.
Two of them have no storefront at all. The Lite plan page states that "The Lite plan doesn't include the online store sales channel", and the Agentic plan page lists "Online Store" first among the features that "aren't available with the Agentic plan". No theme, no product page, nowhere for a timer to render. The other two have a storefront but almost no control over it: Starter says "Other themes and customization options aren't available on the Starter plan", and Retail says "You can't use any other theme with the Retail plan" and "Further customization options aren't available on the Retail plan". Both restrict you to the Spotlight theme, neither page says whether the code editor is reachable, and both are closed to new stores, so treat Starter and Retail as unconfirmed rather than as a flat no.
Decide where the deadline goes before you paste anything
A countdown is not one feature, it is a placement decision. Under the buy button it answers a question the shopper is already asking. In a bar across the top of the store it reaches people browsing a collection who have not picked an item yet. On the cart page it speaks to someone who has chosen and is hesitating. Pick one: three clocks on one journey stop reading as information and start reading as pressure.
| Where you want it | Shopify surface | How you add it | Shows up on |
|---|---|---|---|
| Under the buy button | Product template | Custom Liquid section or block in the theme editor | Every product using that template |
| Across the top of the store | Layout theme.liquid | Edit code, paste before the closing </body> tag | The whole storefront, checkout excluded |
| On the cart page | Cart template | Custom Liquid section in the theme editor | The cart page only |
| Under a blog post | Article main section file | Edit code, sections/main-article.liquid in Dawn | Every blog post |
| Inside checkout | Not reachable this way | Checkout is a separate customization surface | Nothing |
The cart row surprises people. Shopify requires marketplace themes to support sections on every template except customer accounts, gift card and checkout, so the cart page takes a Custom Liquid section just like a product page. Checkout is the real wall, and no theme level code reaches it.
The clock itself, running on this page
Counts down to your date · then shows your message
This is the widget, not a screenshot. On a product page it renders inside your theme's content width.
Add it from the theme editor, without opening a code file
Put both of your Shopify addresses on the same site id
A Shopify store has two web addresses, and a widget cannot tell that they are the same shop. One is the custom domain you set as primary, the one Shopify displays "to customers as they browse your online store" while redirecting the others to it. The other is the
.myshopify.comaddress the store was created with, which Shopify will rename for you exactly once and never again. Add both in the BootSignal dashboard, because the widget resolveslocation.hostnameagainst the addresses registered under one site id, and a page served from the one you skipped renders nothing at all. If you ever spend that single rename, register the new address before you switch.Open the theme editor and switch to the product template
In the Shopify admin go to Online Store, find the theme, and click Edit theme. Use the template dropdown in the center of the top menu bar to switch to the product template, so you are editing what shoppers see on a product rather than on the front page.
Add a Custom Liquid section and paste both lines
In the left sidebar click the Sections icon, then Add section (or Add block inside an existing section) and choose Custom Liquid. Drag it to where the clock belongs, usually just under the price or the add to cart button. Paste the loader and the mount element into the code field, swapping
YOUR_SITE_IDfor the id the dashboard shows beside your domains, then Save.data-langdecides the language of the unit labels under the digits.<script src="https://bootsignal.com/bootsignal.js" data-site-id="YOUR_SITE_ID" data-lang="en" defer></script> <div data-bootsignal="countdown" data-target="2026-12-31T23:59:59" data-expired="This sale has ended."></div>Put your real deadline in data-target
Replace the placeholder timestamp with the moment your discount actually stops, keeping the same shape. Then write
data-expiredas the sentence the page should show once the clock runs out.<div data-bootsignal="countdown" data-target="2026-09-01T23:59:59" data-expired="Sale pricing has ended. Free shipping is still on."></div>Save, then look at a real product URL
The theme editor draws its own overlays on top of section content, so it is a layout check, not a behavior check. Save, open a live product page in an ordinary tab, and watch the numbers move. If nothing renders, check the hostname against your registered domains first.
- The Custom Liquid setting caps its content at 50kb, which no widget snippet approaches.
- Invalid Liquid throws an error on save, and unclosed HTML tags are closed automatically, which can rearrange a half copied snippet. Paste the closing
</div>and</script>with everything else. - The setting cannot use
{% javascript %}or{% stylesheet %}tags, which leaves ordinary HTML and a<script src>as the shape that survives the save here. That is exactly what the loader is. - Keep
deferon the script tag. Shopify's Theme Check flags parser blocking scripts as a storefront slowdown.
A deadline, not a dark pattern
Urgency earns its place when it is true. Your sale ends Sunday at midnight, the clock says so, and a shopper who comes back Monday sees the price they expected. The other kind of timer reads five hours no matter when you arrive, resets on a fresh browser, and has no relationship to any event in your store. Shoppers who notice do not just skip the offer, they stop believing the rest of the page.
BootSignal only does the first kind. data-target is a fixed timestamp, so everyone counts toward the same moment and the clock reaches zero for everyone at once. There is no per visitor mode and no restart. If you extend a sale, you edit the timestamp and save, which is a decision you made rather than a loop the widget runs on its own.
The same rule runs through the catalog. The social proof toast replays only activity your site already recorded, and it has no way to invent a purchase in Ohio that never happened. On a store, that is the difference between social proof and a prop.
One Custom Liquid section, one timestamp, no app install.
If your theme has no Custom Liquid section
Custom Liquid is a Shopify Theme Store requirement, not a platform guarantee. A custom built theme, an off marketplace theme or an old vintage theme can leave it out, and the code editor is what is left when that happens. From the Shopify admin open Online Store, find the theme, click the horizontal menu ("...") icon and choose Edit code. Duplicate the theme first so you have something to fall back to.
Split the two pieces here. The loader goes in the Layout folder, in theme.liquid, before the closing </body> tag, because it should load once on every page. The mount element does not: theme.liquid is the global layout, so a countdown pasted there turns up on your policy pages and your search results.
That means finding the section file, not the template. On an Online Store 2.0 or Horizon era theme the product template is templates/product.json, and Shopify states that "If you're using a JSON template, then any HTML or Liquid code needs to be included in a section". Markup pasted into the JSON breaks the file and the save fails. Open the Sections folder and edit the section that renders the product page. Shopify documents the same rule for blog posts, where Dawn's file is sections/main-article.liquid.
<div data-bootsignal="countdown"
data-target="2026-09-01T23:59:59"
data-expired="Sale pricing has ended."></div>The one mount that does belong in theme.liquid
Store wide messaging is the exception. If every shopper on every page should learn the sale ends Sunday, the global layout is the right home and the announcement bar is built for it. Paste it next to the loader in theme.liquid, before the closing </body> tag, and give each new announcement its own data-id.
<div data-bootsignal="announce"
data-message="Summer sale ends Sunday at midnight"
data-link="/collections/sale"
data-link-text="Shop the sale"
data-id="summer-2026"></div>Dismissible top banner · remembers per visitor
The announcement bar. data-link takes a normal store path, so it can point at the collection the sale applies to.
Keep the bar and the timer in agreement. A bar that says Sunday above a clock that says Saturday is worse than having neither.
What this costs to run
A sale is the week your traffic spikes, which on a metered widget is also the week the invoice does. The meter here is the domain instead: $20 per month or $200 per year per registered domain, every widget included, nothing counted by traffic or pageviews. So the clock on the product page and the bar above it cost the same on a quiet Tuesday as they do on your biggest day of the year. The catalog behind that price is 31 paid widgets plus 31 free browser tools, and widgets released later are included too. A second store is a second domain, priced from the dashboard. Full pricing has the details, and the alternatives section holds the priced comparisons.
Write the sentence that shows when the clock hits zero
Most merchants set data-target carefully and then type something forgettable into data-expired. That is backwards. The expired message runs the longest, sitting on the product page from the moment the sale ends until you notice, which on a busy store can be days.
Give it a job. "The sale has ended" tells a shopper they are late and nothing else. "Sale pricing has ended, free shipping is still on" gives them a reason to stay on the page they already opened.
If the timer does not show up
- Check the hostname in the address bar against your registered domains. A store answering on both a custom domain and
.myshopify.comneeds both registered. - Confirm the loader is on the page exactly once. Pasting it into a Custom Liquid section and into
theme.liquidputs two copies on the same product page. - Look at what the Custom Liquid field saved, not what you pasted. Unclosed tags are closed for you on save, so a snippet that lost its closing
</div>comes back rearranged. - Make sure the mount is on the template you are looking at. A section added to the home page template does not appear on a product, and this one costs people the most time.
- Ask whether the theme was updated since you pasted. Shopify warns that if your code changes are incompatible with a theme update, all your code changes are removed in the updated copy, and it does not spell out how a Custom Liquid section fares, so check a product page after every update.
Nothing you configured lives in the theme except the paste itself. Re-adding the section and retyping the timestamp puts the same clock back, which makes a theme update an annoyance rather than a loss.
Questions people ask
- What time zone does the target date use?
- Whatever you put in
data-targetis parsed as an ISO date-time, and a value with no offset (2026-12-31T23:59:59) is read in each visitor's own local time. That means a shopper in Los Angeles and one in Seoul see the sale end at different moments. For a real deadline, write the offset explicitly:2026-12-31T23:59:59+09:00, orZfor UTC. Everyone then counts down to the same instant. - Is templates/product.json the right place for the countdown?
- No. That file is a manifest rather than a page: it names which sections render and stores the settings you gave them, so raw markup wedged in between makes the JSON invalid and the save is rejected. Shopify's documented rule for these templates is that markup has to live inside a section, which leaves the countdown two homes: a Custom Liquid section added from the theme editor, or the file in the Sections folder that renders your product page.
- Will the countdown run in the theme editor preview?
- Not reliably. The preview runs against your live storefront, not a sandboxed vendor frame, so the digits normally do appear. The catch is what sits on top of them: the editor paints its own overlays over section content, which makes the preview good for checking placement and useless for checking behavior. Save, then open a live product URL in a normal browser tab and watch the numbers change.
- How many countdowns can one page hold?
- Yes. The loader mounts every element it finds, so two
data-bootsignal="countdown"divs with differentdata-targetvalues run independently. The loader itself is still pasted once for the whole theme. - Can I make the timer restart for every visitor?
- No, and that is deliberate.
data-targetis one fixed timestamp, so every shopper counts toward the same moment and the clock expires for everyone at once. An evergreen timer that resets per visitor is a dark pattern, and this widget has no mode that does it. If your deadline moves, you edit the timestamp yourself. - What happens to the install when I update my theme?
- It can disappear. Shopify says that if changes you have made to a theme's code are incompatible with a theme update, all your code changes are removed in the updated copy, and its documentation does not spell out how a Custom Liquid section fares. Duplicate the theme before updating, then load a product page afterward. Re-pasting the loader and the mount element with the same timestamp restores the timer exactly as it was, since nothing about it is stored in the theme.
Register your store domain, then drop the timer into a Custom Liquid section.
Services in this guide
Read next
Where these numbers come from
- Shopify Help Center: Theme editor features overview (Edit theme, Sections sidebar, template dropdown) (checked 2026-08-25)
- Shopify Help Center: Editing theme code (Edit code path, theme update warning, Theme Check parser blocking scripts) (checked 2026-08-25)
- Shopify.dev: Input settings (liquid setting type, 50kb cap, auto closed tags, disallowed tags) (checked 2026-08-25)
- Shopify.dev: Theme Store requirements (Custom Liquid section requirement, templates must support sections) (checked 2026-08-25)
- Shopify Help Center: Basic plan (online store customized through the built in theme editor) (checked 2026-08-25)