Skip to content
ThemesIonic — home
Plugins

Adding a WordPress Countdown Timer

A countdown timer is a few lines of JavaScript. The decisions that matter are fixed versus per-visitor deadlines, time zones, page caching and whether the urgency is real.

5 min read beginner

Some links on this page are affiliate links: if you buy through one, we may earn a commission at no extra cost to you. It does not change what we recommend; see the editorial policy.

A countdown timer should count to a real deadline, computed in the visitor's browser from an absolute timestamp. That one rule handles most of what goes wrong: time zones, page caching, and timers that quietly reset for every visitor. The widget itself is the easy part.

Where the timer comes from

  • Page builders. Elementor's Countdown widget is part of Elementor Pro; Divi includes a Countdown Timer module. If you already pay for one, use it.
  • Block editor. Core has no countdown block. Block plugins add one, or you can use the script below in a Custom HTML block (this needs an administrator account; on multisite only a super admin can save scripts).
  • Dedicated countdown plugins. Worth it for many timers, scheduled campaigns or WooCommerce sale integration.
  • Campaign tools. Lead-capture services run countdowns inside popups and bars, with targeting and testing.

Whichever you pick, check the points below. Most countdown complaints come from the same handful of mistakes, regardless of tool.

Fixed date or evergreen

Type Deadline Good for Risk
Fixed date Same moment for everyone Sales, launches, events, shipping cut-offs Time zone mistakes
Evergreen Starts per visitor on first view Genuine time-limited onboarding offers False urgency if it resets

A fixed-date timer is honest by construction: the sale ends when it says. An evergreen timer starts when a visitor first sees it and is stored in a cookie or local storage. That is legitimate when the offer really does expire for that person — and the server must enforce it, because clearing storage restarts the clock.

A timer that resets on reload, or quietly restarts for a returning visitor, claims a deadline that does not exist. Consumer protection law in the EU and UK lists falsely claiming that an offer is available only for a very limited time as an unfair practice, and regulators elsewhere treat fake urgency as a deceptive design pattern. Beyond the legal exposure, visitors notice: a timer showing the same countdown on Tuesday as on Monday destroys trust in every other claim on the page.

The rule is simple. If the price or offer does not actually change at zero, do not show a timer.

Time zones

WordPress stores a site time zone under Settings → General. Two problems follow:

  1. UTC offsets ignore daylight saving. Choose a city ("Europe/London"), not "UTC+0", or deadlines drift by an hour twice a year.
  2. Visitors are elsewhere. "Ends at midnight" means a different moment in another country. Decide whether the deadline is your midnight or the visitor's, and say which in the copy.

The safe representation is an ISO 8601 timestamp with an offset, such as 2026-11-30T23:59:59+00:00. Every browser parses that to the same absolute moment.

Page caching

A timer that the server renders as "2 days 4 hours left" is wrong for every visitor who gets the cached copy later. The server should output only the deadline; the browser computes what remains. The same principle appears in excluding pages from cache — anything time-dependent cannot be baked into cached HTML.

A minimal timer that follows that rule:

<p class="countdown" data-deadline="2026-11-30T23:59:59+00:00">
  Sale ends <time datetime="2026-11-30T23:59:59+00:00">30 November, 23:59 UK time</time>.
  <span class="countdown-left" aria-hidden="true"></span>
</p>
<script>
document.querySelectorAll('.countdown').forEach(function (el) {
  var end = Date.parse(el.dataset.deadline);
  var out = el.querySelector('.countdown-left');
  function tick() {
    var left = Math.max(0, end - Date.now());
    if (left === 0) {
      el.textContent = 'This offer has ended.';
      return;
    }
    var d = Math.floor(left / 86400000);
    var h = Math.floor(left / 3600000) % 24;
    var m = Math.floor(left / 60000) % 60;
    var s = Math.floor(left / 1000) % 60;
    out.textContent = d + 'd ' + h + 'h ' + m + 'm ' + s + 's left';
    setTimeout(tick, 1000);
  }
  tick();
});
</script>

The sentence with the date stays readable without JavaScript and for screen readers, only the hidden span ticks, the deadline is absolute, and at zero the message changes instead of showing negative numbers.

What happens at zero

Decide this before launch, because the timer is only half of it:

  • The offer must actually end. Schedule the sale price end date in WooCommerce — scheduled sales end at 23:59:59 site time on the end date, so set the timer's deadline to exactly that moment — expire the coupon, or close the form. A timer at zero beside a price that is still discounted is the same honesty problem in reverse.
  • Replace, do not freeze. Show "This offer has ended" or swap in the next offer. A stuck 00:00:00 looks broken.
  • Purge caches if the page content itself changes — clearing the WordPress cache covers each layer.

Accessibility

  • Do not put the ticking element in an aria-live region. Screen readers would announce it every second; leave it with aria-live="off" (the default) and keep a static sentence with the date nearby.
  • Respect prefers-reduced-motion for flip or slide animations.
  • Do not make the timer the only place the deadline is stated. Write the date in the text.

More general checks are in the website accessibility checklist.

Performance

A countdown is cheap if it is a few lines of script. It gets expensive when a plugin loads a font, an animation library and its own styles on every page for one timer. Check that assets load only where a timer exists, and that the digits have a fixed width so the layout does not jitter every second — tabular numerals (font-variant-numeric: tabular-nums) solve that. Large timers above the fold that render late are a layout shift source; reserve their space.

Countdowns in campaigns

A timer inside a popup or bar is where most marketing countdowns live. Hosted tools such as OptinMonster include countdown campaigns (not on the entry plan) with page targeting and A/B testing, so you can show the timer only on the sale pages and only to visitors who have not bought. It is a subscription with a third-party script, so weigh it against the lighter popup plugin options if a single fixed-date timer is all you need.

Common mistakes

  • Server-rendered remaining time behind a page cache.
  • "UTC+0" as the site time zone, so deadlines shift with daylight saving.
  • Evergreen timers that reset, implying a deadline that does not exist.
  • Offer still live at zero because the price or coupon was never scheduled.
  • Live region on the ticker, announcing every second to screen-reader users.

Verify

  1. Set your computer to another time zone and confirm the timer reaches zero at the same absolute moment.
  2. Load the cached page an hour apart and confirm the remaining time is correct both times.
  3. Let a test timer expire and confirm the message changes and the offer is closed.
  4. Check the page with a screen reader running for a minute.

Frequently asked

The Countdown widget is part of Elementor Pro, not the free version. Divi includes a Countdown Timer module. Block themes have no core countdown block, so you need a plugin or a small script.
Usually a time zone mismatch: the deadline was entered in the site's time zone but interpreted in the visitor's, or the WordPress time zone is set to a UTC offset that ignores daylight saving. Store the deadline as an absolute timestamp with an offset.
A per-visitor timer is fine when the offer genuinely expires for that visitor. A timer that resets on reload or for every visit, implying a deadline that does not exist, can breach consumer protection rules against false urgency in the EU, UK and elsewhere.

Related guides