Copy and paste the countdown timer code on your Kajabi landing page (one timer per page). This page holds your time sensitive offer. Paste this code anywhere you want to have the countdown timer into a custom code block.
Optional: Select if you want to hide the timeline funnel code from the url. This makes the url more clean and only works when the cookie from step 2 is active.
Optional: You can also add this code to the thank you page after the first opt-in to show the timer immediately.
<style>
/* Timeline countdown timer code for Kajabi landing pages */
#timer-table {
width: 100%;
border-collapse: collapse;
}
#timer-table td {
text-align: center;
padding: 0px;
}
#timer-table .timer-cell {
font-size: 50px;
font-weight: bold;
}
#timer-table .timer-cell .background-cell {
color: #0f5d4e;
background-color: ;
border-radius: 50%;
width: 80px;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
margin: auto;
}
#timer-table .label-cell {
font-size: 12px;
color: #ab0000;
}
.timercontainer {padding: 20px; background-color: rgba(255, 255, 255, 0.9);}
.flip-card {
perspective: 1000px;
width: 80px;
height: 80px;
display: inline-block;
}
.flip-card-inner {
position: relative;
width: 100%;
height: 100%;
text-align: center;
transition: transform 0.6s;
transform-style: flat;
transform-origin: center center;
}
.flip-card-front, .flip-card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
display: flex;
justify-content: center;
align-items: center;
border-radius: 35%;
}
.flip-card-inner.flipped {
transform: rotateX(180deg);
}
</style>
<div id="timer" class="timercontainer">
<table id="timer-table">
<tr>
<td class="timer-cell"><div class="background-cell" id="dagen"></div></td>
<td class="timer-cell"><div class="background-cell" id="uren"></div></td>
<td class="timer-cell"><div class="background-cell" id="minuten"></div></td>
<td class="timer-cell"><div class="background-cell" id="seconden"></div></td>
</tr>
<tr>
<td class="label-cell" kjb-settings-id="sections_timeline_countdown_settings_days">DAYS</td>
<td class="label-cell" kjb-settings-id="sections_timeline_countdown_settings_hours">HOURS</td>
<td class="label-cell" kjb-settings-id="sections_timeline_countdown_settings_minutes">MINS</td>
<td class="label-cell" kjb-settings-id="sections_timeline_countdown_settings_seconds">SECS</td>
</tr>
</table>
</div>
<script>
// Timeline script for landing page
function isInTestMode() {
const url = window.location.href;
const isKajabiAdmin = url.includes('app.kajabi.com/admin/themes/');
const previewParam = getQueryParam('preview_theme_id');
const hasPreviewParam = previewParam !== null && previewParam !== undefined && previewParam !== '';
return isKajabiAdmin || hasPreviewParam;
}
function getQueryParam(name) {
const params = new URLSearchParams(window.location.search);
return params.get(name);
}
function setCookie(name, value, days) {
let expires = "";
if (days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
const nameEQ = name + "=";
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function updateFlipCard(containerId, value) {
let container = document.getElementById(containerId);
if (!container.querySelector('.flip-card')) {
container.innerHTML = `
<div class="flip-card">
<div class="flip-card-inner">
<div class="flip-card-front"><div class="background-cell">${value}</div></div>
<div class="flip-card-back"><div class="background-cell">${value}</div></div>
</div>
</div>
`;
} else {
const flipCardInner = container.querySelector('.flip-card-inner');
const front = flipCardInner.querySelector('.flip-card-front .background-cell');
const back = flipCardInner.querySelector('.flip-card-back .background-cell');
if (front.innerText != value) {
flipCardInner.classList.add('flipped');
setTimeout(() => {
// Update the front with the new value after the flip animation
front.innerText = value;
flipCardInner.classList.remove('flipped');
// Reset the back's text to be ready for the next flip
back.innerText = front.innerText;
}, 200); // Matches the CSS transition time
}
}
}
const settings = {
setcookie: true,
setcookienumber: "1",
setcookiedays: 90,
tltimeendday: true,
tltimeday: 2,
tltimehour: 0,
tltimemin: 0,
tlenable_end_action: "redirect",
tlaction: "add-url-from-page-without-your-special-offer",
useFlipAnimation: true
};
function isValidTParameter(t) {
var open = '\\{\\{';
var content = '.*';
var close = '\\}\\}';
var regex = new RegExp('^' + open + content + close + '$');
return !regex.test(t);
}
// Hoofdlogica
const encodedData = getQueryParam('t');
if (encodedData) {
if (settings.setcookie && isValidTParameter(encodedData)) {
setCookie(`timeline${settings.setcookienumber}`, encodedData, settings.setcookiedays);
}
process(encodedData);
} else {
const cookieData = getCookie(`timeline${settings.setcookienumber}`);
if (cookieData) {
process(cookieData);
} else {
process(null);
}
}
function process(encodedData) {
const isTestMode = isInTestMode(); // Test mode
let tlctmInt;
if (isTestMode) {
const nu = new Date().getTime();
dayhourmin = (settings.tltimeday * 86400000) + (settings.tltimehour * 3600000) + (settings.tltimemin * 60000);
var endday = 0;
if (settings.tltimeendday) {
endday = resterendeTijdTotEindeVanDag(nu);
}
var timeremaining = nu + dayhourmin + endday;
timelineCountdown(timeremaining, settings.useFlipAnimation);
return;
} else if (encodedData) { // Timer found
const tlcdt = encodedData.toString().split("").reverse().join("");
const tlcsomEnd = tlcdt.indexOf("dC");
const tlcsom = parseInt(tlcdt.substring(2, tlcsomEnd), 10);
const tlctmEnd = tlcdt.indexOf("Gt");
const tlctm = tlcdt.substring(tlcsomEnd + 6, tlctmEnd);
const tlctmInt = parseInt(tlctm);
const tlcalsom = [...tlctm].reduce((sum, num) => sum + parseInt(num, 10), 0);
const tlgrt = tlcdt.match(/Hrf(.+?)fU/)?.[1];
const tlgrtl = tlctm.length;
if (tlcdt.indexOf("R1969") !== -1 && tlcdt.indexOf("dC3729") !== -1 && tlcalsom == tlcsom && tlgrt == tlgrtl) {
var currentTime = new Date().getTime();
var timeElapsed = currentTime - tlctmInt; // Time since the timer started
var dayhourmin = (settings.tltimeday * 86400000 + settings.tltimehour * 3600000 + settings.tltimemin * 60000);
var endday = 0;
if (settings.tltimeendday) {
endday = resterendeTijdTotEindeVanDag(tlctmInt);
}
var endtime = tlctmInt + dayhourmin + endday
var timeremaining = endtime - currentTime;
if (endtime > currentTime) { // Timer still active
window.onload = function() {
timelineCountdown(endtime, settings.useFlipAnimation);
};
} else { // Timer ended
handleEndAction();
}
} else { // Invalid or no timer code
handleEndAction();
}
} else { // No timer at all
handleEndAction();
}
}
function handleEndAction() {
if (settings.tlenable_end_action === "redirect") {
window.location.replace(settings.tlaction);
}
}
function timelineCountdown(enddate, useFlipAnimation) {
var timer = setInterval(function() {
var huidigeTijd = new Date().getTime();
var verschil = parseInt(enddate, 10) - parseInt(huidigeTijd, 10);
if (verschil >= 0) {
var dagen = Math.floor(verschil / (1000 * 60 * 60 * 24));
var uren = Math.floor((verschil % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minuten = Math.floor((verschil % (1000 * 60 * 60)) / (1000 * 60));
var seconden = Math.floor((verschil % (1000 * 60)) / 1000);
// Determine if flip animation should be used
if (useFlipAnimation) {
// Update using flip animation
updateFlipCard("dagen", dagen);
updateFlipCard("uren", uren);
updateFlipCard("minuten", minuten);
updateFlipCard("seconden", seconden);
} else {
// Directly update the numbers without flip animation
document.getElementById("dagen").innerHTML = dagen;
document.getElementById("uren").innerHTML = uren;
document.getElementById("minuten").innerHTML = minuten;
document.getElementById("seconden").innerHTML = seconden;
}
} else {
clearInterval(timer);
const isTestMode = isInTestMode(); // Testmode
if (!isTestMode) {
handleEndAction();
}
}
}, 1000);
}
function resterendeTijdTotEindeVanDag(tijdstempel) {
var startDay = new Date(tijdstempel);
var eindeVanDag = new Date(tijdstempel);
eindeVanDag.setHours(23, 59, 59, 999);
return eindeVanDag.getTime() - startDay.getTime();
}
</script>