Create a form in Kajabi with a unique Timeline form field. Do NOT make this new form field mandatory. Add an automation to start an email sequence. Select this form in the sidebar. Save the page to run the field finder script.
YOUR FORM FIELD FINDER SETTINGS:
Kajabi Form selected:
No custom form fields are found. You might need to refresh this page to run the search script.
Step 2: Timeline Funnel Settings
Copy the Timeline form field ID from step 1 to the sidebar. A cookie is needed to add extra security to your funnel. You can deselect the cookie option if you don't want to use a cookie or when you want to test your funnel.
Running multiple Timeline Funnels on the same site? Use a different Field ID for each funnel. Each funnel needs its own unique field to track visitors independently.
YOUR FUNNEL SETTINGS:
Timeline Form Field ID: 7
Cookie will be set for 90 days
Step 3: Funnel Starting Trigger
Kick off your funnel with an opt-in form on a landing page or via a Zapier trigger.
START WITH AN OPT-IN FORM AND LANDING PAGE
3.1: Copy the code from this trigger. Customize your opt-in page and paste the code at the end of the page in a custom-code block.
3.2: In the opt-in form on this page add the original full URL (no internal page link) to the thank you page.
<style>
/* Timeline code for Kajabi form and landing page */
#form_submission_custom_7 {display: none;}
</style>
<script>
(function testModePreflight() {
var params = new URLSearchParams(window.location.search);
if (!params.has('jiffytestmode')) return;
document.cookie.split(';').forEach(function (c) {
var name = c.split('=')[0].trim();
if (/^timeline\d+$/.test(name)) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
}
});
alert('Timeline Funnel test mode active. All cookies are cleared');
})();
function setCookie(name, value, days) {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
document.cookie = `${name}=${value};expires=${date.toUTCString()};path=/`;
}
function deleteCookie(name) {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
}
// Main code
var inputElement = document.querySelector('input[name="thank_you_url"]');
let tlrdt = "";
let cookietrue = false;
const settings = {
setcookie: true,
tlcustom: 7,
setcookienumber: 7, // update to follow the custom field number v3.1.2
setcookiedays: 90
};
const cookies = document.cookie.split(';').map(cookie => cookie.trim());
const timelineCookie = cookies.find(cookie => cookie.startsWith(`timeline${settings.setcookienumber}=`));
if (!settings.setcookie) {
deleteCookie(`timeline${settings.setcookienumber}`);
}
if (timelineCookie) {
tlrdt = timelineCookie.substring(`timeline${settings.setcookienumber}=`.length);
cookietrue = true;
}
function updateField() {
const tltm = Date.now();
const tlsom = Array.from(tltm.toString()).reduce((acc, curr) => acc + parseInt(curr, 10), 0);
const tltmGrootte = tltm.toString().length;
const tldt = `tL${tlsom}dC3729${tltm}GtR1969Hrf${tltmGrootte}fU`;
tlrdt = tldt.split("").reverse().join("");
document.querySelectorAll(`#form_submission_custom_${settings.tlcustom}`).forEach(el => {
el.value = tlrdt;
});
}
function updateURL(tlrdt) {
if (inputElement) {
const url = new URL(inputElement.value, window.location.origin);
url.searchParams.set('t', tlrdt);
inputElement.value = url.pathname + url.search;
}
}
if (!timelineCookie && !tlrdt) {
updateField();
} else if (tlrdt) {
document.querySelectorAll(`#form_submission_custom_${settings.tlcustom}`).forEach(el => {
el.value = tlrdt;
});
}
document.getElementById("form-button").addEventListener("click", function() {
if (!cookietrue && settings.setcookie) {
updateField()
setCookie(`timeline${settings.setcookienumber}`, tlrdt, settings.setcookiedays);
setTimeout(() => {
deleteCookie(`timeline${settings.setcookienumber}`);
}, 5000); // 5000 milliseconden = 5 seconden
} else if (!settings.setcookie) {
updateField()
deleteCookie(`timeline${settings.setcookienumber}`);
}
updateURL(tlrdt)
});
</script>
No opt-in page URL found. Add your opt-in page URL in Step 3 to generate your test link in step 8.
Countdown Timer Setup
Step 4: Configure Expiration Settings
Select the duration of the countdown timer, calculated from the moment the trigger became active. Optionally, configure what happens when the timer expires — for example, redirect visitors to a page without the special offer.
YOUR TIMER SETTINGS:
2 Days, 0 Hours, 0 Mins
Plus the remaining time until midnight in the customer's local timezone.
No redirect URL found. Add a redirect URL in the Step 4 settings.
Step 5: Countdown Timer Layout
Style the countdown timer layout. The changes can be seen in the timer on top of this page.
Optional: You can change this width of the countdown timer in the settings to match the block size on your landing page.
Step 6: Special Offer Landing Page
The countdown code is split into two parts.
Part 1 – Top of page (redirect guard): Paste this once into a Custom Code block at the very top of your landing page. It runs before any content is rendered and immediately redirects expired visitors. Contains no visible HTML.
Part 2 – Timer display: Paste this wherever you want the countdown timer to appear. Can be placed multiple times on the same page for multiple timers. Requires Part 1 to be present on the same page.
Optional: You can also add both parts to the thank-you page after the first opt-in to show the timer immediately.
YOUR LANDING PAGE COUNTDOWN TIMER SETTING:
Default setting: Timeline code is shown in the url
Part 1 — Redirect guard REQUIRED
Paste once into a Custom Code block at the very top of your landing page. Contains no visible HTML.
Part 2 — Timer display
Paste wherever you want the countdown timer to appear. Can be added multiple times. Requires Part 1 to be on the same page.
<script>
// Timeline Guard Script - Part 1 - Mandatory
(function() {
var isAdmin = window.location.href.includes('app.kajabi.com/admin/themes/') ||
new URLSearchParams(window.location.search).has('preview_theme_id');
if (!isAdmin) document.body.style.display = 'none';
})();
function isInTestMode() {
const url = window.location.href;
const isKajabiAdmin = url.includes('app.kajabi.com/admin/themes/');
const previewParam = getQueryParam('preview_theme_id');
const testModeParam = new URLSearchParams(window.location.search).has('jiffytestmode');
return isKajabiAdmin || previewParam || testModeParam;
}
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 deleteCookie(name) {
document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
}
function getCookie(name) {
const nameEQ = name + "=";
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i].trim();
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function hideQuery() {
if (!isInTestMode()) {
var url = window.location.href;
var newUrl = url.split('?')[0];
history.replaceState({}, document.title, newUrl);
}
}
const settings = {
setcookie: true,
setcookienumber: "7",
setcookiedays: 90,
tltimeendday: true,
tltimeday: 2,
tltimehour: 0,
tltimemin: 0,
tlenable_end_action: "redirect",
tlaction: "",
useFlipAnimation: false,
tlredirect_delay: false,
tlredirect_delay_seconds: 5,
tlredirect_delay_message: "This offer has expired. Redirecting in X seconds...",
tlenable_expired_message: true,
tlexpired_message: "This offer has ended."
};
window.TL = window.TL || {};
window.TL.settings = settings;
function isValidTParameter(t) {
const regex = new RegExp('^\\{\\{.*\\}\\}$');
return !regex.test(t);
}
function resterendeTijdTotEindeVanDag(tijdstempel) {
var eindeVanDag = new Date(tijdstempel);
eindeVanDag.setHours(23, 59, 59, 999);
return eindeVanDag.getTime() - tijdstempel;
}
function handleEndAction() {
if (!isInTestMode() && settings.tlenable_end_action === "redirect") {
if (settings.tlredirect_delay) {
document.body.style.display = '';
function showRedirectMessage() {
var delaySecs = settings.tlredirect_delay_seconds || 5;
var msgEl = document.createElement('div');
msgEl.className = 'tl-redirect-message';
msgEl.innerText = (settings.tlredirect_delay_message || 'Redirecting in {n} seconds...').replace('{n}', delaySecs);
msgEl.style.cssText = 'position:fixed;inset:0;z-index:99999;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,0.95);font-size:24px;font-weight:bold;color:#333;text-align:center;padding:40px;';
document.body.appendChild(msgEl);
var countdownInt = setInterval(function() {
delaySecs--;
if (delaySecs <= 0) {
clearInterval(countdownInt);
window.location.replace(settings.tlaction);
} else {
msgEl.innerText = (settings.tlredirect_delay_message || 'Redirecting in {n} seconds...').replace('{n}', delaySecs);
}
}, 1000);
}
if (document.readyState === 'loading') {
window.addEventListener('DOMContentLoaded', showRedirectMessage);
} else {
showRedirectMessage();
}
} else {
window.location.replace(settings.tlaction);
}
} else if (settings.tlenable_end_action === "none" && settings.tlenable_expired_message) {
document.body.style.display = '';
function showExpiredMessage() {
var expiredEl = document.createElement('div');
expiredEl.className = 'tl-expired-message';
expiredEl.innerText = settings.tlexpired_message || 'This offer has ended.';
expiredEl.style.cssText = 'position:fixed;inset:0;z-index:99999;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,0.95);font-size:24px;font-weight:bold;color:#333;text-align:center;padding:40px;';
document.body.appendChild(expiredEl);
}
if (document.readyState === 'loading') {
window.addEventListener('DOMContentLoaded', showExpiredMessage);
} else {
showExpiredMessage();
}
} else {
document.body.style.display = '';
}
}
function process(encodedData) {
if (isInTestMode()) {
if (window.TL.endTime && new Date().getTime() < window.TL.endTime) {
window.TL.settings = settings;
document.body.style.display = '';
return;
}
const now = new Date().getTime();
const offset = (settings.tltimeday * 86400000) + (settings.tltimehour * 3600000) + (settings.tltimemin * 60000);
const endOfDay = settings.tltimeendday ? resterendeTijdTotEindeVanDag(now) : 0;
const endTime = now + offset + endOfDay;
window.TL.endTime = endTime;
document.body.style.display = '';
document.dispatchEvent(new CustomEvent('tl:ready', { detail: { endTime: endTime } }));
(function() {
var guardTimer = setInterval(function() {
if (new Date().getTime() >= endTime) {
clearInterval(guardTimer);
handleEndAction();
}
}, 1000);
})();
return;
}
if (!encodedData) return handleEndAction();
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, n) => sum + parseInt(n, 10), 0);
const tlgrt = tlcdt.match(/Hrf(.+?)fU/)?.[1];
const tlgrtl = tlctm.length;
if (tlcdt.includes("R1969") && tlcdt.includes("dC3729") && tlcalsom == tlcsom && tlgrt == tlgrtl) {
const now = new Date().getTime();
const offset = (settings.tltimeday * 86400000) + (settings.tltimehour * 3600000) + (settings.tltimemin * 60000);
const endOfDay = settings.tltimeendday ? resterendeTijdTotEindeVanDag(tlctmInt) : 0;
const endTime = tlctmInt + offset + endOfDay;
if (endTime > now) {
window.TL.endTime = endTime;
document.body.style.display = '';
document.dispatchEvent(new CustomEvent('tl:ready', { detail: { endTime: endTime } }));
(function() {
var guardTimer = setInterval(function() {
if (new Date().getTime() >= endTime) {
clearInterval(guardTimer);
handleEndAction();
}
}, 1000);
})();
} else {
handleEndAction();
}
} else {
handleEndAction();
}
}
function startTimer() {
try {
if (new URLSearchParams(window.location.search).has('jiffytestmode')) {
document.cookie.split(';').forEach(function(c) {
var name = c.split('=')[0].trim();
if (/^timeline\d+$/.test(name)) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
}
});
process(null);
return;
}
const encodedData = getQueryParam('t');
if (settings.setcookie) {
if (encodedData && isValidTParameter(encodedData)) {
setCookie(`timeline${settings.setcookienumber}`, encodedData, settings.setcookiedays);
}
} else {
deleteCookie(`timeline${settings.setcookienumber}`);
}
const cookieData = getCookie(`timeline${settings.setcookienumber}`);
process(encodedData || cookieData);
} catch (err) {
console.error("Timeline Funnel error:", err);
document.body.style.display = '';
}
}
startTimer();
</script>
Paste the address of your special offer page from step 6 into the settings. This generates a personalised link you can use in your Kajabi email sequences — when a subscriber clicks it, their countdown timer starts.
Optional: If you use a third-party email tool like ActiveCampaign, forward the timeline field to that tool and replace the placeholder with its merge tag.
The code ?t={{custom_7}} must be added to the end of the page url to personalize the link.
YOUR EMAIL LINK:
No URL found. Add your special offer page URL in Step 7 to generate your email link.
Step 8: Test Your Funnel
Before going live, test your funnel to verify your funnel works correctly.
Use the test links below and open them in a different browser than your Kajabi admin account.
The opt-in and special offer page URLs have ?jiffytestmode appended — this clears cookies and resets the timer on every page load.
Do not use these URLs in your live funnel.
YOUR OPT-IN PAGE TEST URL (UPDATE URL IN STEP 3):
No opt-in page URL found. Add your opt-in page URL in Step 3 to generate your test link.
YOUR SPECIAL OFFER PAGE TEST URL (UPDATE URL IN STEP 7):
No special offer page URL found. Add your special offer page URL in Step 7 to generate this test link.