Countdown Timers on Paywalls
Add a live countdown timer to a Superwall paywall with Liquid: count down from when the paywall opens, from install, or to a fixed sale end date, and hide the offer when time runs out.
A countdown timer shows how long an offer lasts, such as "Offer ends in 14
". In Superwall, a timer is a text element whose text uses thecountdown_from Liquid filter. It updates every second while the paywall is on screen, and needs no code in your app.
Add a timer
-
In the paywall editor, add a Text element, or select an existing one.
-
Set its text to a countdown. For a 15-minute timer that starts when the paywall opens:
{{ device.localDateTime | date_add: "15m" | countdown_from: state.now }} -
Preview the paywall. The text counts down from
0:15:00.
countdown_from takes the date the countdown ends on its left, and the date it counts from after the colon. Use state.now, the current time, as the start: referencing it makes the text re-render every second.
Choose when the timer ends
The end date decides whether the timer restarts:
| Count down to | End date | Restarts |
|---|---|---|
| A time after the paywall opens | device.localDateTime | date_add: "15m" | Every time the paywall opens |
| A time after install | device.appInstallDate | date_add: "3d" | Never; it's the same for each user |
| A fixed date, such as a sale's end | "2026-12-01T08:00:00Z" | Never; it's the same for everyone |
| A date your app sends | A user attribute or placement parameter holding an ISO 8601 date | When your app changes the date |
For example, a 3-day launch offer that every user gets once, counted from install:
Your offer ends in {{ device.appInstallDate | date_add: "3d" | countdown_from: state.now, "long_most_significant", "days" }}This shows 3 days, then 2 days, and so on down to the last hours and minutes.
Adding and subtracting time
date_add and date_subtract shift a date. Pass a duration such as "30s", "15m", "2h", "3d", "1w", "1M" or "1y", or a number and a unit:
{{ device.localDateTime | date_add: "90m" }}
{{ device.localDateTime | date_add: 3, "days" }}
{{ "2026-12-01T08:00:00Z" | date_subtract: "1d" }}Capital M is months and lowercase m is minutes. date_add: "1M" adds a month.
Format the timer
countdown_from takes up to four options, in order:
{{ end_date | countdown_from: state.now, style, max_unit, column }}-
style: how the countdown is written. The default is
digital.Style Example digital2:03:04narrow2h 3m 4sshort2 hr, 3 min, 4 seclong2 hours, 3 minutes, 4 secondslong_most_significant2 hours: only the largest unit -
max_unit: the largest unit to show. The default is
hours, so 3 days shows as72:00:00. Passdaysto show3 days, 0:00:00instead, or3 dayswith thelongstyle. The options areyears,months,weeks,days,hours,minutesandseconds. -
column: return just one unit, as a number, for building your own layout. For example,
47:12:03with the column set tominutesreturns12.
To show each unit in its own box, use one text element per unit:
{{ device.localDateTime | date_add: "1h" | countdown_from: state.now, "digital", "hours", "minutes" }}{{ device.localDateTime | date_add: "1h" | countdown_from: state.now, "digital", "hours", "seconds" }}A column returns a plain number, so pad it yourself if you want two digits:
{% assign s = device.localDateTime | date_add: "1h" | countdown_from: state.now, "digital", "hours", "seconds" %}{% if s < 10 %}0{% endif %}{{ s }}Show it in the user's language
countdown_from writes units in English. Add localize_countdown with a language code to write them in another language:
{{ device.appInstallDate | date_add: "3d" | countdown_from: state.now, "digital", "days" | localize_countdown: device.deviceLanguageCode }}On a French device, 1 day, 3:30:10 becomes 1 j et 3:30:10. For the rest of the paywall's text, see Paywall Localization.
When the timer runs out
countdown_from expects the end date to be later than the start. Once the end date passes, the numbers go negative. To show something else instead, read the seconds left as a number and check it:
{% assign left = device.appInstallDate | date_add: "3d" | countdown_from: state.now, "digital", "seconds", "seconds" %}{% if left > 0 %}Ends in {{ device.appInstallDate | date_add: "3d" | countdown_from: state.now }}{% else %}This offer has ended{% endif %}To show a different paywall once an offer ends, target the users who should still see it with an audience filter, such as device.daysSinceInstall less than 3.
Things to know
- The timer runs only while the paywall is on screen. It doesn't schedule anything on the device.
device.localDateTimeis the device's clock, so a user who changes their clock changes the timer. Use a date your server sends when that matters.- A countdown is display only. It doesn't end a discount in the App Store or Google Play. End the offer with your campaign or product setup too.
- Make sure the countdown is honest. See Are paywall events and urgency messaging App Store compliant?
Related
How is this guide?
Monthly Billing Plans for Annual Subscriptions
Sell an annual App Store subscription as 12 monthly payments with Superwall. Add Apple's monthly billing plan to the product, choose monthly installments or up-front billing per paywall, and compare the two in charts.
Exit Offer Paywalls
Show a second paywall, such as a discount, when a user closes your paywall without buying. Set it up with the paywall_decline placement and an audience filter.