Loading…
(function(){ const API = 'https://api.listentolip.com/v1'; const DEFAULT_LIBRARY = 'https://libraryon.org/'; const root = document.getElementById('lip-app'); const sourceHint = (new URLSearchParams(location.search).get('s') || '').trim().toLowerCase(); function gaEvent(name, params){ try{ if(window.gtag) window.gtag('event', name, params || {}); }catch(e){} } function episodeIdFromLocation(){ const pathMatch = location.pathname.match(/^\/ep\/?(\d+)\/?$/i); if(pathMatch) return Number(pathMatch[1]); const params = new URLSearchParams(location.search); const q = Number(params.get('ep') || params.get('episode')); return Number.isInteger(q) && q > 0 ? q : null; } async function api(path) { let lastError; for (let attempt = 0; attempt < 3; attempt++) { try { const res = await fetch(API + path, { headers: { Accept: 'application/json' }, cache: 'no-store' }); if (!res.ok) { throw new Error('HTTP ' + res.status); } const payload = await res.json(); if (!payload || payload.ok !== true) { throw new Error( payload && payload.code ? payload.code : 'API error' ); } return payload.data; } catch (err) { lastError = err; if (attempt < 2) { await new Promise(resolve => setTimeout(resolve, 1200 * (attempt + 1)) ); } } } throw lastError; } function el(tag, className, text){ const node = document.createElement(tag); if(className) node.className = className; if(text !== undefined && text !== null) node.textContent = text; return node; } function addLink(parent, label, href, tone, eventName, eventParams){ if(!href) return; const a = el('a', 'lip-btn ' + (tone || 'lip-btn-secondary'), label); a.href = href; a.target = '_blank'; a.rel = eventName === 'amazon_click' ? 'nofollow sponsored noopener' : 'noopener'; a.addEventListener('click', function(){ gaEvent(eventName || 'outbound_click', eventParams || {}); }); parent.appendChild(a); } function formatRelease(iso){ if(!iso) return ''; const d = new Date(iso); if(Number.isNaN(d.getTime())) return ''; return new Intl.DateTimeFormat('en-GB', { weekday:'long', day:'numeric', month:'long', hour:'2-digit', minute:'2-digit', timeZone:'Europe/London' }).format(d); } function byline(ep){ const bits = []; if(ep.author) bits.push('by ' + ep.author); if(ep.illustrator) bits.push('illustrated by ' + ep.illustrator); return bits.join(' · '); } function clear(){ root.innerHTML = ''; } function renderHidden(id){ clear(); const card = el('section','lip-card lip-soft'); card.appendChild(el('p','lip-eyebrow','Lifted Imagination Podcast')); card.appendChild(el('h1','lip-title','Episode ' + id + ' is still a secret')); card.appendChild(el('p','lip-copy','The book for this episode is still under wraps. Check back when it has been announced.')); const actions = el('div','lip-actions'); const home = el('a','lip-btn lip-btn-primary','See what’s available now'); home.href = '/'; actions.appendChild(home); card.appendChild(actions); root.appendChild(card); } function renderMissing(id){ clear(); const card = el('section','lip-card'); card.appendChild(el('p','lip-eyebrow','Lifted Imagination Podcast')); card.appendChild(el('h1','lip-title','We couldn’t find Episode ' + id)); card.appendChild(el('p','lip-copy','Check the episode number, or head back to the latest story.')); const actions = el('div','lip-actions'); const home = el('a','lip-btn lip-btn-primary','Go to the latest story'); home.href = '/'; actions.appendChild(home); card.appendChild(actions); root.appendChild(card); } function renderBookActions(card, ep){ const heading = el('h2','lip-section-title', ep.state === 'announced' ? 'Get ready to read along' : 'Need the book?'); card.appendChild(heading); const actions = el('div','lip-actions'); addLink(actions, 'Find it at your library', ep.libraryUrl || DEFAULT_LIBRARY, 'lip-btn-secondary', 'library_click', {episode_id:ep.episodeId, source_hint:sourceHint || '(none)'}); addLink(actions, 'View on Amazon', ep.amazonUrl, ep.state === 'announced' ? 'lip-btn-primary' : 'lip-btn-mid', 'amazon_click', {episode_id:ep.episodeId, book_title:ep.bookTitle, source_hint:sourceHint || '(none)'}); card.appendChild(actions); if(ep.amazonUrl){ card.appendChild(el('small','lip-disclosure','As an Amazon Associate I earn from qualifying purchases, at no additional cost to you.')); } } function renderEpisode(data){ if(!data.found){ renderMissing(data.episodeId); return; } const ep = data.episode; if(ep.state === 'hidden'){ renderHidden(ep.episodeId); return; } clear(); document.title = ep.bookTitle ? ep.bookTitle + ' — Lifted Imagination Podcast' : 'Lifted Imagination Podcast'; const hero = el('section','lip-card'); const back = el('a','lip-back','← Lifted Imagination'); back.href = '/'; back.addEventListener('click', function(){ gaEvent('home_click',{ from_episode:ep.episodeId, source_hint:sourceHint || '(none)' }); }); hero.appendChild(back); hero.appendChild(el('p','lip-eyebrow', ep.state === 'announced' ? 'Coming next · Episode ' + ep.episodeId : 'Episode ' + ep.episodeId)); hero.appendChild(el('h1','lip-title lip-book-title',ep.bookTitle || ('Episode ' + ep.episodeId))); const by = byline(ep); if(by) hero.appendChild(el('p','lip-byline',by)); if(ep.releaseAt) hero.appendChild(el('p','lip-meta', ep.state === 'announced' ? 'Available ' + formatRelease(ep.releaseAt) : 'Follow along with your copy of the book.')); if(ep.state === 'announced'){ hero.appendChild(el('p','lip-copy',"Get the book ready now, then come back for the episode and we'll read it together.")); hero.appendChild(el('div','lip-divider')); renderBookActions(hero,ep); } else { if(ep.episodeDescription) hero.appendChild(el('p','lip-copy',ep.episodeDescription)); hero.appendChild(el('div','lip-divider')); hero.appendChild(el('h2','lip-section-title','Listen and follow along')); const listen = el('div','lip-actions'); const links = ep.listen || {}; addLink(listen,'Spotify',links.spotify,'lip-btn-primary','listen_click',{platform:'spotify',episode_id:ep.episodeId,source_hint:sourceHint || '(none)'}); addLink(listen,'Apple Podcasts',links.apple,'lip-btn-secondary','listen_click',{platform:'apple',episode_id:ep.episodeId,source_hint:sourceHint || '(none)'}); addLink(listen,'Amazon Music',links.amazonMusic,'lip-btn-secondary','listen_click',{platform:'amazon_music',episode_id:ep.episodeId,source_hint:sourceHint || '(none)'}); addLink(listen,'YouTube',links.youtube,'lip-btn-secondary','listen_click',{platform:'youtube',episode_id:ep.episodeId,source_hint:sourceHint || '(none)'}); if(!listen.children.length) listen.appendChild(el('p','lip-meta','Listening links are being updated.')); hero.appendChild(listen); hero.appendChild(el('div','lip-divider')); renderBookActions(hero,ep); } root.appendChild(hero); if(data.next && data.next.state !== 'hidden'){ const next = el('section','lip-card lip-soft'); next.appendChild(el('p','lip-eyebrow','Next on Lifted Imagination Podcast')); next.appendChild(el('h2','lip-section-title lip-book-title',data.next.bookTitle || ('Episode ' + data.next.episodeId))); const nextBy = byline(data.next); if(nextBy) next.appendChild(el('p','lip-byline',nextBy)); next.appendChild(el('p','lip-copy','Get the next book ready now.')); const a = el('a','lip-btn lip-btn-low','Get ready for Episode ' + data.next.episodeId); a.href = '/ep' + data.next.episodeId; const actions = el('div','lip-actions'); actions.appendChild(a); next.appendChild(actions); root.appendChild(next); } if(data.previous && data.previous.state === 'live'){ const previousNav = el('div','lip-prev-nav'); const previousLink = el('a','lip-back','← Previous episode'); previousLink.href = '/ep' + data.previous.episodeId; previousLink.addEventListener('click', function(){ gaEvent('previous_episode_click',{ from_episode:ep.episodeId, to_episode:data.previous.episodeId, source_hint:sourceHint || '(none)' }); }); previousNav.appendChild(previousLink); root.appendChild(previousNav); } gaEvent('episode_page_view',{episode_id:ep.episodeId,state:ep.state,source_hint:sourceHint || '(none)'}); } function miniCard(label, ep, action, tone){ const card = el('section','lip-card'); card.appendChild(el('p','lip-eyebrow',label)); card.appendChild(el('h2','lip-section-title lip-book-title', ep ? ep.bookTitle : 'Nothing scheduled yet')); if(ep){ const by = byline(ep); if(by) card.appendChild(el('p','lip-byline',by)); const actions = el('div','lip-actions'); const a = el('a','lip-btn ' + (tone || 'lip-btn-primary'),action); a.href = '/ep' + ep.episodeId; actions.appendChild(a); card.appendChild(actions); } return card; } function renderHome(data){ clear(); const intro = el('section','lip-card lip-soft'); intro.appendChild(el('p','lip-eyebrow','Lifted Imagination Podcast')); intro.appendChild(el('h1','lip-title lip-home-title','We read together.')); intro.appendChild(el('p','lip-copy',"Get the latest episode's physical book, press play, help turn the pages, and follow along.")); root.appendChild(intro); const grid = el('div','lip-home-grid'); grid.style.marginTop = '14px'; grid.appendChild(miniCard('Latest Episode · Read with me now',data.current,'Start this episode','lip-btn-primary')); grid.appendChild(miniCard('Next episode · Get the book ready',data.next,'Get the book ready','lip-btn-mid')); root.appendChild(grid); gaEvent('podcast_home_view',{source_hint:sourceHint || '(none)'}); } async function init(){ try{ const id = episodeIdFromLocation(); if(id){ const data = await api('/episode/' + id); renderEpisode(data); } else { const data = await api('/home'); renderHome(data); } }catch(err){ console.error(err); clear(); const card = el('section','lip-card'); card.appendChild(el('h2','lip-section-title','We couldn’t load this just now.')); card.appendChild(el('p','lip-copy','Please refresh the page and try again.')); root.appendChild(card); gaEvent('lip_load_error',{message:String(err && err.message ? err.message : err)}); } } init(); })();
(function () { const TURNSTILE_SITE_KEY = '0x4AAAAAAEhCEjz-fElkR9vh'; const API_URL = 'https://api.listentolip.com/v1/subscribe'; const root = document.getElementById('lip-email'); const homeIntro = document.getElementById('lip-email-home-intro'); const episodeIntro = document.getElementById('lip-email-episode-intro'); const revealButton = document.getElementById('lip-email-reveal'); const formWrap = document.getElementById('lip-email-form-wrap'); const form = document.getElementById('lip-email-form'); const emailInput = document.getElementById('lip-email-address'); const submitButton = document.getElementById('lip-email-submit'); const message = document.getElementById('lip-email-message'); const params = new URLSearchParams(window.location.search); const path = window.location.pathname; const episodeMatch = path.match(/^\/ep(\d+)\/?$/i); const isHome = path === '/'; let turnstileWidgetId = null; let formVisible = false; function trackEmailEvent( eventName, extra ) { if (typeof window.gtag !== 'function') { return; } const episodeId = episodeMatch ? Number(episodeMatch[1]) : null; window.gtag( 'event', eventName, Object.assign( { source_hint: params.get('s') || '', signup_path: path, signup_surface: isHome ? 'home' : 'episode', signup_episode_id: episodeId }, extra || {} ) ); } function showForm() { formWrap.hidden = false; formVisible = true; renderTurnstile(); window.setTimeout(function () { emailInput.focus({ preventScroll: true }); }, 0); } function renderTurnstile() { if ( !formVisible || turnstileWidgetId !== null || !window.turnstile ) { return; } turnstileWidgetId = window.turnstile.render( '#lip-turnstile', { sitekey: TURNSTILE_SITE_KEY, action: 'subscribe', theme: 'auto', size: 'flexible', appearance: 'interaction-only' } ); } window.lipTurnstileReady = function () { renderTurnstile(); }; if (isHome) { root.classList.add('lip-email-home'); root.hidden = false; homeIntro.hidden = false; episodeIntro.hidden = true; showForm(); } else if (episodeMatch) { const episodeId = Number(episodeMatch[1]); fetch( 'https://api.listentolip.com/v1/episode/' + episodeId ) .then(function (response) { if (!response.ok) { throw new Error( 'episode_lookup_failed' ); } return response.json(); }) .then(function (result) { const state = result && result.ok && result.data && result.data.episode ? result.data.episode.state : 'hidden'; if (state === 'hidden') { return; } root.hidden = false; homeIntro.hidden = true; episodeIntro.hidden = false; formWrap.hidden = true; }) .catch(function () { /* * Fail closed: * if episode state is unknown, * don't add email UI. */ }); } revealButton.addEventListener( 'click', function () { trackEmailEvent( 'email_signup_reveal' ); revealButton.hidden = true; showForm(); } ); form.addEventListener( 'submit', async function (event) { event.preventDefault(); message.textContent = ''; message.classList.remove( 'lip-email-success' ); const turnstileToken = window.turnstile && turnstileWidgetId !== null ? window.turnstile.getResponse( turnstileWidgetId ) : ''; if (!turnstileToken) { message.textContent = 'Please complete the verification first.'; return; } trackEmailEvent( 'email_signup_submit' ); const payload = { email: emailInput.value, turnstile_token: turnstileToken, source_hint: params.get('s') || '', signup_path: path, signup_episode_id: episodeMatch ? Number(episodeMatch[1]) : null }; submitButton.disabled = true; submitButton.textContent = 'Sending…'; try { const response = await fetch( API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) } ); const result = await response.json(); if ( response.ok && result.ok === true ) { trackEmailEvent( 'email_signup_success' ); message.textContent = 'Check your inbox to confirm your email.'; message.classList.add( 'lip-email-success' ); emailInput.disabled = true; submitButton.hidden = true; return; } trackEmailEvent( 'email_signup_error', { error_code: result.code || 'unknown_error' } ); message.textContent = 'Something went wrong. Please try again.'; if ( window.turnstile && turnstileWidgetId !== null ) { window.turnstile.reset( turnstileWidgetId ); } } catch (error) { trackEmailEvent( 'email_signup_error', { error_code: 'network_error' } ); message.textContent = 'Something went wrong. Please try again.'; if ( window.turnstile && turnstileWidgetId !== null ) { window.turnstile.reset( turnstileWidgetId ); } } finally { if (!submitButton.hidden) { submitButton.disabled = false; submitButton.textContent = "Tell me what's next"; } } } ); })();

← Lifted Imagination


YOUR PRIVACYLast updated: 30 August 2026Lifted Imagination Podcast (LIP) is operated by Billy Champion.If you have a question about your personal information or want to exercise any of your privacy rights, contact:
[email protected]

Analytics settings

(function () { const MEASUREMENT_ID = 'G-H3KN00X6KH'; const STORAGE_KEY = 'lip_analytics_optout'; const status = document.getElementById( 'lip-analytics-status' ); const button = document.getElementById( 'lip-analytics-toggle' ); function analyticsIsOff() { try { return ( localStorage.getItem( STORAGE_KEY ) === '1' ); } catch (error) { return ( window[ 'ga-disable-' + MEASUREMENT_ID ] === true ); } } function clearAnalyticsCookies() { document.cookie .split(';') .forEach(function (cookie) { const name = cookie .split('=')[0] .trim(); if ( name === '_ga' || name.indexOf('_ga_') === 0 ) { document.cookie = name + '=; Max-Age=0; path=/'; document.cookie = name + '=; Max-Age=0; path=/; domain=.listentolip.com'; } }); } function render() { const isOff = analyticsIsOff(); if (isOff) { status.textContent = 'Analytics are off for this browser.'; button.textContent = 'Turn analytics back on'; button.setAttribute( 'aria-pressed', 'true' ); } else { status.textContent = 'LIP uses privacy-limited analytics to understand how the site is used and to improve it.'; button.textContent = 'Turn off analytics'; button.setAttribute( 'aria-pressed', 'false' ); } } button.addEventListener( 'click', function () { if (analyticsIsOff()) { try { localStorage.removeItem( STORAGE_KEY ); } catch (error) {} window[ 'ga-disable-' + MEASUREMENT_ID ] = false; window.location.reload(); return; } window[ 'ga-disable-' + MEASUREMENT_ID ] = true; try { localStorage.setItem( STORAGE_KEY, '1' ); } catch (error) {} clearAnalyticsCookies(); render(); } ); render(); })();

EMAIL SUBSCRIPTIONSIf you sign up for LIP emails, we collect your email address so we can send you information about upcoming books, new episodes and occasional extras from LIP.We also keep information needed to manage your subscription, including whether your email is pending, confirmed or unsubscribed; when you signed up, confirmed or unsubscribed; and a record of your consent.We may also record how you reached the signup form, such as the page or episode you signed up from and a source reference attached to the link. We use this to understand which parts of LIP help people discover the email list.We rely on your consent to send these emails. You can withdraw that consent at any time by using the unsubscribe link included in our emails.1ST TO YOUR INBOXEmail subscribers may be told what book LIP is reading next before that book is announced publicly on the website.Your email address is used for this and the other LIP email purposes described above. We do not sell your email address or give it to other organisations for their own marketing.WEBSITE, ANALYTICS AND SECURITYWe use technical information about visits to the LIP website to operate, secure and improve the site.Google Analytics is used to understand things such as which pages are visited, how people reach LIP and how visitors interact with the site.You can turn analytics off for this browser at any time using the Analytics settings above.Cloudflare helps operate and secure the website. This includes Cloudflare Turnstile, which is used on the email signup form to help distinguish genuine visitors from automated or abusive submissions.SERVICE PROVIDERSWe use service providers to run LIP, including:Carrd — website publishing
Cloudflare — website infrastructure, security and subscriber data storage
Resend — email delivery
Google Analytics — website analytics
These providers may process information on our behalf where necessary to provide their services.Some providers may process information in countries outside the UK. Where personal information is transferred internationally, applicable data-protection safeguards are used.HOW LONG WE KEEP INFORMATIONWe keep information only for as long as reasonably necessary for the purposes described in this notice.Subscriber information is retained while your subscription is active.If you unsubscribe, we may retain the minimum information reasonably necessary to record your opt-out, make sure you are not emailed again without a new signup, and maintain an appropriate record of consent and withdrawal.Unconfirmed signup information is retained only for as long as reasonably necessary to operate and manage the signup process.YOUR RIGHTSDepending on the circumstances, you may have rights over your personal information including the right to ask for access to it, correction of inaccurate information, deletion, restriction of its use, or a copy of information you have provided.You also have the right to object to certain uses of your information and to withdraw consent where processing is based on consent.To make a request, email [email protected].You also have the right to complain to the UK Information Commissioner's Office (ICO) if you are unhappy with how your personal information has been handled.CHILDRENLIP's email list is intended for adults, including parents, carers and educators. Children should not submit their own email address to the LIP email list without the involvement of a parent or guardian.CHANGES TO THIS NOTICEWe may update this privacy notice if the way LIP handles personal information changes. The latest version will always be available on this page.


← Lifted Imagination