<!-- OneTrust Cookies Consent Notice start for lightyear.cloud --> <script src="https://cdn-ukwest.onetrust.com/scripttemplates/otSDKStub.js" type="text/javascript" charset="UTF-8" data-domain-script="0197a69a-8630-7f3b-bd4c-caeb8c6dff1c" ></script> <script type="text/javascript"> (function () { // --- your allowlist of gated vendors + required OneTrust groups --- var RULES = [ // VWO { test: /\/\/dev\.visualwebsiteoptimizer\.com\//i, groups: ["C0003"] }, // YouTube - C0003 { test: /\/\/www\.youtube\.com\//i, groups: ["C0003"] }, { test: /\/\/youtube\.com\//i, groups: ["C0003"] }, { test: /\/\/www\.youtube-nocookie\.com\//i, groups: ["C0003"] }, { test: /\/\/youtubei\.googleapis\.com\//i, groups: ["C0003"] }, { test: /\/\/i\.ytimg\.com\//i, groups: ["C0003"] }, { test: /\/\/s\.ytimg\.com\//i, groups: ["C0003"] }, { test: /\/\/yt3\.ggpht\.com\//i, groups: ["C0003"] }, // Vimeo - C0003 { test: /\/\/player\.vimeo\.com\//i, groups: ["C0003"] }, { test: /\/\/vimeo\.com\//i, groups: ["C0003"] }, { test: /\/\/f\.vimeocdn\.com\//i, groups: ["C0003"] }, { test: /\/\/i\.vimeocdn\.com\//i, groups: ["C0003"] }, // Calendly - C0003 //{ test: /\/\/calendly\.com\//i, groups: ["C0003"] }, //{ test: /\/\/assets\.calendly\.com\//i, groups: ["C0003"] }, //{ test: /\/\/cdn\.calendly\.com\//i, groups: ["C0003"] }, // Existing C0004 domains { test: /\/\/munchkin\.marketo\.net\//i, groups: ["C0004"] }, { test: /\/\/cdn\.bizible\.com\//i, groups: ["C0004"] }, { test: /\/\/bizible\.com\//i, groups: ["C0004"] }, { test: /\/\/cdn\.bizibly\.com\//i, groups: ["C0004"] }, { test: /\/\/adobedc\.net\//i, groups: ["C0004"] }, { test: /\/\/a\.omappapi\.com\//i, groups: ["C0004"] }, { test: /\/\/tracker\.gaconnector\.com\//i, groups: ["C0004"] }, { test: /\/\/static\.hotjar\.com\//i, groups: ["C0004"] }, { test: /\/\/js\.hs\-scripts\.com\//i, groups: ["C0004"] }, { test: /\/scripts\/custom\-gclid\.js\//i, groups: ["C0004"] }, // HubSpot - C0004 { test: /\/\/js\.hubspot\.com\//i, groups: ["C0004"] }, { test: /\/\/js\.hsforms\.net\//i, groups: ["C0004"] }, { test: /\/\/js\.hscta\.net\//i, groups: ["C0004"] }, { test: /\/\/js\.hsadspixel\.net\//i, groups: ["C0004"] }, { test: /\/\/js\.hs\-analytics\.net\//i, groups: ["C0004"] }, { test: /\/\/js\.hs\-banner\.com\//i, groups: ["C0004"] }, // Bing - C0004 { test: /\/\/bat\.bing\.com\//i, groups: ["C0004"] }, { test: /\/\/clarity\.ms\//i, groups: ["C0004"] }, { test: /\/\/c\.bing\.com\//i, groups: ["C0004"] }, { test: /\/\/www\.bing\.com\/api\//i, groups: ["C0004"] }, // MSN - C0004 { test: /\/\/c\.msn\.com\//i, groups: ["C0004"] }, { test: /\/\/www\.msn\.com\/api\//i, groups: ["C0004"] }, // LinkedIn - C0005 { test: /\/\/snap\.licdn\.com\//i, groups: ["C0005"] }, { test: /\/\/px\.ads\.linkedin\.com\//i, groups: ["C0005"] }, { test: /\/\/www\.linkedin\.com\/px\//i, groups: ["C0005"] }, { test: /\/\/platform\.linkedin\.com\//i, groups: ["C0005"] }, ]; function matchRule(src) { for (var i = 0; i < RULES.length; i++) if (RULES[i].test.test(src)) return RULES[i]; return null; } function hasConsent(req) { var g = (window.OneTrustActiveGroups || window.OnetrustActiveGroups || "").split(","); return req.every(function (id) { return g.indexOf(id) !== -1; }); } function isMunchkinNode(node) { var src = node.getAttribute("data-gated-src") || node.getAttribute("src") || ""; return /\/\/munchkin\.marketo\.net\//i.test(src); } // --- Restore a blocked script element (preserve attrs + handlers) --- function restoreScript(node) { var replayQ = null; // --- Munchkin-specific handoff: remove stub so real lib can install itself if (isMunchkinNode(node) && window.Munchkin && window.Munchkin.__otStub) { replayQ = window.Munchkin.__q ? window.Munchkin.__q.slice() : null; try { delete window.Munchkin; } catch (e) { window.Munchkin = undefined; } } var s = document.createElement("script"); // copy common attrs [ "src", "async", "defer", "noModule", "crossorigin", "referrerpolicy", "integrity", "nonce", ].forEach(function (a) { var v = node.getAttribute(a); if (v !== null) s.setAttribute(a, v); }); // restore type (module vs classic). If plain, default to classic JS. var t = node.getAttribute("type"); s.type = t && t !== "text/plain" ? t : "text/javascript"; // copy handlers if any were set as properties if (node.onload) s.onload = node.onload; if (node.onerror) s.onerror = node.onerror; if (node.onreadystatechange) s.onreadystatechange = node.onreadystatechange; // inline support (rare for your RULES) if (node.text && !s.src) s.text = node.text; // when real script finishes loading, replay any queued calls if (isMunchkinNode(node) && replayQ) { s.addEventListener("load", function () { if (window.Munchkin && typeof window.Munchkin.init === "function") { replayQ.forEach(function (item) { var method = item[0], args = item[1] || []; if (typeof window.Munchkin[method] === "function") { window.Munchkin[method].apply(window.Munchkin, args); } }); } }); } node.replaceWith(s); } function restoreAllEligible() { // Only restore nodes whose vendor is allowed now var nodes = document.querySelectorAll( 'script.optanon-blocked[type="text/plain"][data-gated-src]' ); for (var i = 0; i < nodes.length; i++) { var n = nodes[i]; var src = n.getAttribute("data-gated-src") || n.getAttribute("src") || ""; var rule = matchRule(src); if (rule && hasConsent(rule.groups)) restoreScript(n); } } // --- Iframe and Video blocking for video platforms --- var IFRAME_RULES = [ { test: /youtube\.com|youtube-nocookie\.com|youtu\.be/i, groups: ["C0003"] }, { test: /vimeo\.com|player\.vimeo\.com/i, groups: ["C0003"] }, //{ test: /calendly\.com/i, groups: ["C0003"] } ]; var VIDEO_RULES = [ { test: /youtube\.com|youtube-nocookie\.com|youtu\.be/i, groups: ["C0003"] }, { test: /vimeo\.com|player\.vimeo\.com|vimeocdn\.com/i, groups: ["C0003"] }, { test: /wistia\.com|fast\.wistia/i, groups: ["C0003"] }, { test: /brightcove\.com|players\.brightcove/i, groups: ["C0003"] }, { test: /vidyard\.com/i, groups: ["C0003"] }, { test: /jwplayer\.com|jwpcdn\.com/i, groups: ["C0003"] }, { test: /cloudinary\.com/i, groups: ["C0003"] }, { test: /streamable\.com/i, groups: ["C0003"] } ]; function matchIframeRule(src) { for (var i = 0; i < IFRAME_RULES.length; i++) if (IFRAME_RULES[i].test.test(src)) return IFRAME_RULES[i]; return null; } function matchVideoRule(src) { for (var i = 0; i < VIDEO_RULES.length; i++) if (VIDEO_RULES[i].test.test(src)) return VIDEO_RULES[i]; return null; } // Generate unique ID for each video var videoIdCounter = 0; // Function to create placeholder element with unique ID function createPlaceholder(type, uniqueId) { var placeholder = document.createElement("div"); placeholder.className = "optanon-video-placeholder"; if (uniqueId) { placeholder.id = "optanon-placeholder-" + uniqueId; // Add unique ID for videos } placeholder.style.cssText = "position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;padding:20px;background:rgba(0,0,0,0.8);color:white;border-radius:5px;z-index:10;"; placeholder.innerHTML = "<p>Video Consent Required</p><p>This " + type + " requires your consent to load content from third-party providers.</p><button onclick='window.OneTrust.ToggleInfoDisplay()' style='margin-top: 15px; padding:12px 24px;background:#E4173F;color:white;border:none;border-radius:24px;cursor:pointer;font-size:16px;cursor:pointer;'>Manage Preferences</button>"; return placeholder; } // Function to block HTML5 video element function blockVideo(video) { var src = video.getAttribute("src") || video.getAttribute("data-src") || ""; // Check all source elements within the video tag var sources = video.querySelectorAll("source"); var needsBlocking = false; var rule = null; // Check main video src if (src) { rule = matchVideoRule(src); if (rule) needsBlocking = true; } // Check source elements for (var i = 0; i < sources.length; i++) { var sourceSrc = sources[i].getAttribute("src") || ""; var sourceRule = matchVideoRule(sourceSrc); if (sourceRule) { needsBlocking = true; rule = sourceRule; break; } } // Also check for third-party video platforms even without explicit rules if (!needsBlocking && video.hasAttribute("data-require-consent")) { needsBlocking = true; rule = { groups: ["C0003"] }; } if (!needsBlocking) return; if (rule && hasConsent(rule.groups)) return; // Check if already blocked if (video.hasAttribute("data-blocked")) return; // Generate unique ID for this video var uniqueId = ++videoIdCounter; // Store original sources and block the video video.setAttribute("data-consent-required", rule.groups.join(",")); video.setAttribute("data-video-unique-id", uniqueId); video.className += (video.className ? " " : "") + "optanon-blocked-video"; // Store and remove sources if (video.src) { video.setAttribute("data-blocked-src", video.src); video.removeAttribute("src"); } // Store source elements data and remove them var sourcesData = []; for (var j = 0; j < sources.length; j++) { sourcesData.push({ src: sources[j].src, type: sources[j].type, media: sources[j].media }); } if (sourcesData.length > 0) { video.setAttribute("data-blocked-sources", JSON.stringify(sourcesData)); // Remove source elements while (video.firstChild) { video.removeChild(video.firstChild); } } // Add placeholder styling video.style.position = "relative"; video.style.backgroundColor = "#f0f0f0"; video.style.minHeight = video.style.height || "315px"; video.style.minWidth = video.style.width || "560px"; // Disable video controls and autoplay video.removeAttribute("autoplay"); video.removeAttribute("controls"); video.setAttribute("data-blocked", "true"); // Create placeholder with unique ID var placeholder = createPlaceholder("video", uniqueId); // Position parent if needed if (video.parentElement) { if (video.parentElement.style.position !== "absolute" && video.parentElement.style.position !== "relative" && video.parentElement.style.position !== "fixed") { video.parentElement.style.position = "relative"; } video.parentElement.appendChild(placeholder); video.setAttribute("data-placeholder-id", placeholder.id); } } // Function to restore blocked videos function restoreBlockedVideos() { var videos = document.querySelectorAll("video.optanon-blocked-video"); for (var i = 0; i < videos.length; i++) { var video = videos[i]; var requiredGroups = (video.getAttribute("data-consent-required") || "").split(","); if (hasConsent(requiredGroups)) { // Remove placeholder using the stored ID var placeholderId = video.getAttribute("data-placeholder-id"); if (placeholderId) { var placeholder = document.getElementById(placeholderId); if (placeholder) { placeholder.remove(); } } // Also try to remove any placeholder in the parent (fallback) if (video.parentElement) { var allPlaceholders = video.parentElement.querySelectorAll(".optanon-video-placeholder"); allPlaceholders.forEach(function(p) { p.remove(); }); } // Restore main src var blockedSrc = video.getAttribute("data-blocked-src"); if (blockedSrc) { video.src = blockedSrc; video.removeAttribute("data-blocked-src"); } // Restore source elements var sourcesData = video.getAttribute("data-blocked-sources"); if (sourcesData) { try { var sources = JSON.parse(sourcesData); for (var j = 0; j < sources.length; j++) { var source = document.createElement("source"); source.src = sources[j].src; if (sources[j].type) source.type = sources[j].type; if (sources[j].media) source.media = sources[j].media; video.appendChild(source); } } catch (e) { console.error("Error parsing video sources:", e); } video.removeAttribute("data-blocked-sources"); } // Restore video attributes video.setAttribute("controls", "true"); video.removeAttribute("data-blocked"); video.removeAttribute("data-consent-required"); video.removeAttribute("data-placeholder-id"); video.removeAttribute("data-video-unique-id"); video.className = video.className.replace("optanon-blocked-video", "").trim(); // Clear inline styles that were added for blocking video.style.backgroundColor = ""; video.style.minHeight = ""; video.style.minWidth = ""; video.style.position = ""; // Reload video video.load(); } } // Clean up any orphaned placeholders (safety measure) var orphanedPlaceholders = document.querySelectorAll(".optanon-video-placeholder"); orphanedPlaceholders.forEach(function(placeholder) { // Check if there's a corresponding blocked video var uniqueId = placeholder.id.replace("optanon-placeholder-", ""); var correspondingVideo = document.querySelector('[data-video-unique-id="' + uniqueId + '"]'); // If no corresponding blocked video exists, or if consent is granted, remove the placeholder if (!correspondingVideo || !correspondingVideo.hasAttribute("data-blocked")) { placeholder.remove(); } }); } // Function to block iframe function blockIframe(iframe) { var src = iframe.getAttribute("src") || iframe.getAttribute("data-src") || ""; var rule = matchIframeRule(src); if (!rule) return; // not a targeted iframe if (hasConsent(rule.groups)) return; // consent already granted // Store original src and block the iframe if (iframe.src) { iframe.setAttribute("data-blocked-src", iframe.src); iframe.removeAttribute("src"); } iframe.setAttribute("data-consent-required", rule.groups.join(",")); iframe.className += (iframe.className ? " " : "") + "optanon-blocked-iframe"; // Add placeholder styling iframe.style.backgroundColor = "#f0f0f0"; iframe.style.minHeight = iframe.style.minHeight || "315px"; // Create placeholder message var placeholder = createPlaceholder("video"); // If iframe has parent, add placeholder if (iframe.parentElement && iframe.parentElement.style.position !== "absolute" && iframe.parentElement.style.position !== "relative") { iframe.parentElement.style.position = "relative"; } if (iframe.parentElement) { iframe.parentElement.appendChild(placeholder); iframe.setAttribute("data-placeholder-id", placeholder.className); } } // Function to restore blocked iframes function restoreBlockedIframes() { var iframes = document.querySelectorAll("iframe.optanon-blocked-iframe"); for (var i = 0; i < iframes.length; i++) { var iframe = iframes[i]; var blockedSrc = iframe.getAttribute("data-blocked-src"); var requiredGroups = (iframe.getAttribute("data-consent-required") || "").split(","); if (blockedSrc && hasConsent(requiredGroups)) { // Remove placeholder var placeholder = iframe.parentElement ? iframe.parentElement.querySelector(".optanon-video-placeholder") : null; if (placeholder) placeholder.remove(); // Restore iframe iframe.src = blockedSrc; iframe.removeAttribute("data-blocked-src"); iframe.removeAttribute("data-consent-required"); iframe.className = iframe.className.replace("optanon-blocked-iframe", "").trim(); iframe.style.backgroundColor = ""; iframe.style.minHeight = ""; } } } // Override createElement to catch dynamically created iframes var originalCreateElement = document.createElement; document.createElement = function(tagName) { var element = originalCreateElement.call(document, tagName); if (tagName.toLowerCase() === "iframe") { // Use setter to intercept src assignment var srcDescriptor = Object.getOwnPropertyDescriptor(element, "src") || Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "src"); Object.defineProperty(element, "src", { get: function() { return this.getAttribute("src"); }, set: function(value) { var rule = matchIframeRule(value); if (rule && !hasConsent(rule.groups)) { this.setAttribute("data-blocked-src", value); this.className += (this.className ? " " : "") + "optanon-blocked-iframe"; this.setAttribute("data-consent-required", rule.groups.join(",")); } else { srcDescriptor.set.call(this, value); } }, configurable: true }); } return element; }; // Hook DOM insertions for iframes and videos ["appendChild", "insertBefore", "replaceChild"].forEach(function (m) { var orig = Node.prototype[m]; Node.prototype[m] = function (child) { if (child) { if (child.tagName === "IFRAME") { try { blockIframe(child); } catch (e) {} } else if (child.tagName === "VIDEO") { try { blockVideo(child); } catch (e) {} } } var result = orig.apply(this, arguments); // Also check after insertion in case src is set after adding to DOM if (child) { if (child.tagName === "IFRAME") { setTimeout(function() { blockIframe(child); }, 0); } else if (child.tagName === "VIDEO") { setTimeout(function() { blockVideo(child); }, 0); } } return result; }; }); // Monitor existing iframes and videos on page load function blockExistingMedia() { var iframes = document.querySelectorAll("iframe"); for (var i = 0; i < iframes.length; i++) { blockIframe(iframes[i]); } var videos = document.querySelectorAll("video"); for (var j = 0; j < videos.length; j++) { blockVideo(videos[j]); } } // MutationObserver for iframes and videos added via innerHTML or other methods var mediaObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { mutation.addedNodes.forEach(function(node) { if (node.tagName === "IFRAME") { blockIframe(node); } else if (node.tagName === "VIDEO") { blockVideo(node); } // Check for iframes and videos in added subtree if (node.querySelectorAll) { var iframes = node.querySelectorAll("iframe"); for (var i = 0; i < iframes.length; i++) { blockIframe(iframes[i]); } var videos = node.querySelectorAll("video"); for (var j = 0; j < videos.length; j++) { blockVideo(videos[j]); } } }); }); }); // Start observing when DOM is ready if (document.body) { mediaObserver.observe(document.body, { childList: true, subtree: true }); blockExistingMedia(); } else { document.addEventListener("DOMContentLoaded", function() { mediaObserver.observe(document.body, { childList: true, subtree: true }); blockExistingMedia(); }); } // --- Block Bizible/Marketo pixel tracking images --- function blockTrackingPixels() { // Block img elements that are tracking pixels var images = document.querySelectorAll('img'); images.forEach(function(img) { var src = img.src || img.getAttribute('src') || ''; if (src.includes('bizible.com') || src.includes('bizibly.com') || src.includes('adobedc.net')) { if (!hasConsent(['C0004'])) { img.setAttribute('data-blocked-src', src); img.removeAttribute('src'); img.style.display = 'none'; } } }); } // Monitor for tracking pixels var pixelObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { mutation.addedNodes.forEach(function(node) { if (node.tagName === 'IMG') { var src = node.src || node.getAttribute('src') || ''; if (src.includes('bizible.com') || src.includes('bizibly.com') || src.includes('adobedc.net')) { if (!hasConsent(['C0004'])) { node.setAttribute('data-blocked-src', src); node.removeAttribute('src'); node.style.display = 'none'; } } } }); }); }); if (document.body) { pixelObserver.observe(document.body, { childList: true, subtree: true }); blockTrackingPixels(); } // --- Handle custom video implementations with click-to-load --- function interceptVideoButtons() { // Find all elements that look like they'll load a video on click var videoContainers = document.querySelectorAll('.js-video[data-video-url], .video[data-video-url]'); videoContainers.forEach(function(container) { var videoUrl = container.getAttribute('data-video-url'); if (!videoUrl) return; // Check if this is a YouTube or Vimeo URL that needs consent var needsConsent = false; var requiredGroups = []; if (/youtube\.com|youtu\.be/.test(videoUrl)) { needsConsent = true; requiredGroups = ["C0003"]; } else if (/vimeo\.com/.test(videoUrl)) { needsConsent = true; requiredGroups = ["C0003"]; } if (!needsConsent || hasConsent(requiredGroups)) return; // Find the play button within this container var playButton = container.querySelector('.js-videoPlay, button[type="button"]'); if (!playButton) return; // Store original click handler if it exists var originalOnclick = playButton.onclick; playButton.setAttribute('data-consent-required', requiredGroups.join(',')); playButton.setAttribute('data-original-video-url', videoUrl); // Replace click handler with consent check playButton.onclick = function(e) { e.preventDefault(); e.stopPropagation(); if (hasConsent(requiredGroups)) { // Restore original behavior if consent granted if (originalOnclick) { originalOnclick.call(this, e); } else { // Try to trigger the video load manually if no onclick was stored this.click(); } } else { // Show consent modal showVideoConsentModal(container, requiredGroups); } return false; }; // Also intercept addEventListener for this button var originalAddEventListener = playButton.addEventListener; playButton.addEventListener = function(type, listener, options) { if (type === 'click') { // Wrap the click listener var wrappedListener = function(e) { if (!hasConsent(requiredGroups)) { e.preventDefault(); e.stopPropagation(); showVideoConsentModal(container, requiredGroups); return false; } return listener.call(this, e); }; originalAddEventListener.call(this, type, wrappedListener, options); } else { originalAddEventListener.call(this, type, listener, options); } }; }); } // Function to show consent modal for custom video implementations function showVideoConsentModal(container, requiredGroups) { // Check if modal already exists var existingModal = container.querySelector('.optanon-video-consent-modal'); if (existingModal) { existingModal.style.display = 'block'; return; } // Create consent modal overlay var modal = document.createElement('div'); modal.className = 'optanon-video-consent-modal'; modal.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);display:flex;align-items:center;justify-content:center;z-index:1000;'; var modalContent = document.createElement('div'); modalContent.style.cssText = 'background:white;padding:30px;border-radius:8px;text-align:center;max-width:400px; margin: 10% auto;'; modalContent.innerHTML = '<h3 style="margin:0 0 15px 0;color:#11111;">Video consent required</h3>' + '<p style="margin:0 0 20px 0;color:#11111;">This video requires your consent to load content from third-party providers.</p>' + '<button onclick="window.OneTrust.ToggleInfoDisplay()" style="padding:12px 24px;background:#E4173F;color:white;border:none;border-radius:24px;cursor:pointer;font-size:16px;margin-right:10px;">Manage preferences</button>' + '<button onclick="this.closest(\'.optanon-video-consent-modal\').style.display=\'none\'" style="padding:12px 24px;background:#F7F7F7;color:#11111;border:none;border-radius:24px;cursor:pointer;font-size:16px;">Cancel</button>'; modal.appendChild(modalContent); container.style.position = 'relative'; container.appendChild(modal); } // Re-check video buttons after consent changes function recheckVideoButtons() { var buttons = document.querySelectorAll('[data-consent-required]'); buttons.forEach(function(button) { var requiredGroups = (button.getAttribute('data-consent-required') || '').split(','); if (hasConsent(requiredGroups)) { // Remove consent modal if it exists var container = button.closest('.js-video, .video'); if (container) { var modal = container.querySelector('.optanon-video-consent-modal'); if (modal) modal.remove(); } } }); } // Initialize video button interception if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { setTimeout(interceptVideoButtons, 100); // Small delay to ensure other scripts have initialized }); } else { setTimeout(interceptVideoButtons, 100); } // Re-run interception periodically to catch dynamically added videos setInterval(interceptVideoButtons, 2000); // --- Hook DOM insertions for dynamically-added scripts (your original bit) --- function handleScript(node) { var src = node.getAttribute("src") || ""; var rule = matchRule(src); if (!rule) return; // not targeted if (hasConsent(rule.groups)) return; // consent already granted node.setAttribute("data-gated-src", src); node.type = "text/plain"; node.className += (node.className ? " " : "") + "optanon-blocked"; } ["appendChild", "insertBefore"].forEach(function (m) { var orig = Node.prototype[m]; Node.prototype[m] = function (child) { if (child && child.tagName === "SCRIPT") { try { handleScript(child); } catch (e) {} } return orig.apply(this, arguments); }; }); // --- NEW: Patch document.write / writeln (covers your example) --- function gateHtml(html) { // normalize (strip surrounding whitespace) var s = String(html); // Find <script ... src="..."> and if URL matches a RULE without consent, // rewrite to type="text/plain" and mark for later restore. // This regex is intentionally simple; it handles typical cases. return s.replace( /<script\b([^>]*?)\bsrc\s*=\s*(['"])([^'"]+)\2([^>]*)>(?:<\/script>)?/gi, function (_m, pre, q, src, post) { var rule = matchRule(src || ""); if (!rule || hasConsent(rule.groups)) return _m; // leave as-is // ensure we keep original attrs, add our markers, and suppress execution var attrs = (pre || "") + " src=" + q + src + q + (post || ""); // remove existing type if present; we'll set text/plain attrs = attrs.replace(/\btype\s*=\s*(['"])[^'"]*\1/gi, ""); attrs += ' type="text/plain" class="optanon-blocked" data-gated-src="' + src.replace(/"/g, "&quot;") + '"'; return "\<script " + attrs + "\>\<\/script\>"; } ); } ["write", "writeln"].forEach(function (m) { var orig = document[m]; document[m] = function () { // Join arguments (browsers allow multiple) var html = Array.prototype.join.call(arguments, ""); var gated = gateHtml(html); return orig.call(document, gated); }; }); // Cookie blocking - Enhanced to catch iframe cookies const originalCookieDescriptor = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie'); // Block postMessage from YouTube iframes before consent const originalPostMessage = window.postMessage; window.postMessage = function(message, targetOrigin) { if (targetOrigin && targetOrigin.includes('youtube.com') && !hasConsent(['C0003'])) { return; } return originalPostMessage.apply(this, arguments); }; const cookiePatterns = { C0003: [ // VWO cookies /_vwo/, // YouTube cookies - more comprehensive patterns /^YSC/, /^VISITOR_INFO/, /^VISITOR_PRIVACY/, /^PREF/, /^GPS/, /^CONSENT/, /_Secure-ROLLOUT/, /^LOGIN_INFO/, /^SIDCC/, /^SSID/, /^APISID/, /^SAPISID/, /^HSID/, /^SID/, /^DEVICE_INFO/, /^CONSISTENCY/, /^use_hitbox/, /^remote_sid/, // Vimeo cookies /^vuid/, /^player/, /^_abexps/, /^_gcl/, /^continuous_play/, /^has_logged_in/, // Calendly cookies (removed GA cookies as they're handled in GTM) //_calendly/, /^calendly/ ], C0004: [ // Existing patterns /gaconnector/, /_biz/, /_vis/, // Marketo/Bizible cookies - more comprehensive (includes _BUID) /_BUID/, /^_BUID$/, /^_biz_uid/, /^_biz_nA/, /^_biz_pendingA/, /^_biz_sid/, /^_biz_flagsA/, /^mkto_/, /^_mkto_trk/, /^_mkt_disp/, /^_mkt_trk/, // HubSpot cookies /__hs/, /hubspot/, /__hst/, /__hsc/, /__hssc/, /__hssrc/, // Bing cookies /_uet/, /MUID/, /_clck/, /_clsk/, // MSN cookies (often shared with Bing) /MSN/ ], C0005: [ // LinkedIn cookies /^li_/, /^lidc/, /^bcookie/, /^bscookie/, /^lang/, /^UserMatchHistory/, /^AnalyticsSyncHistory/ ] }; Object.defineProperty(Document.prototype, 'cookie', { get: function() { return originalCookieDescriptor.get.call(this); }, set: function(value) { const cookieName = value.split('=')[0].trim(); // Allow OneTrust cookies if (cookieName.startsWith('OptAnon')) { return originalCookieDescriptor.set.call(this, value); } // Allow all Cloudflare security cookies regardless of domain if (cookieName === '__cf_bm' || cookieName === '_cf_bm') { return originalCookieDescriptor.set.call(this, value); } // Check against patterns for (const category in cookiePatterns) { if (!hasConsent([category])) { for (const pattern of cookiePatterns[category]) { if (pattern.test(cookieName)) { return; } } } } return originalCookieDescriptor.set.call(this, value); }, configurable: true }); // --- Storylane: notify demos when consent is available --- function notifyStorylaneConsent() { // Using C0003 here – same group as YouTube / Calendly / Vimeo if (!hasConsent(["C0003"])) return; var storylaneDemos = document.querySelectorAll("iframe[name='sl-embed']"); for (var i = 0; i < storylaneDemos.length; i++) { var slDemo = storylaneDemos[i]; try { if (slDemo.contentWindow) { slDemo.contentWindow.postMessage( { message: "storylane-cookie-consent" }, "*" ); } } catch (e) { // swallow – don't break anything if one iframe is grumpy } } } // --- Force refresh after initial Accept All click --- function bindDirectAcceptRefresh() { function attach() { var acceptBtn = document.getElementById("onetrust-accept-btn-handler"); if (!acceptBtn || acceptBtn.getAttribute("data-refresh-bound") === "true") return; acceptBtn.setAttribute("data-refresh-bound", "true"); acceptBtn.addEventListener("click", function() { try { if (sessionStorage.getItem("__ot_accept_refresh_done") === "true") return; } catch (e) {} setTimeout(function() { try { sessionStorage.setItem("__ot_accept_refresh_done", "true"); } catch (e) {} location.reload(); }, 500); }); } // bind now if button already exists attach(); // keep trying briefly in case OneTrust injects banner slightly later var tries = 0; var maxTries = 40; var timer = setInterval(function() { tries++; attach(); if (tries >= maxTries || document.getElementById("onetrust-accept-btn-handler")) { clearInterval(timer); } }, 250); } // --- Consent change: restore anything now allowed --- window.addEventListener("OneTrustGroupsUpdated", function() { restoreAllEligible(); restoreBlockedIframes(); restoreBlockedVideos(); recheckVideoButtons(); notifyStorylaneConsent(); }); // Optional: if your snippet might run after some writes already happened // scan current DOM once: document.querySelectorAll("script[src]").forEach(function (n) { try { handleScript(n); } catch (e) {} }); bindDirectAcceptRefresh(); restoreAllEligible(); notifyStorylaneConsent(); // --- OPTIONAL SAFETY: stub Munchkin to avoid ReferenceError before load --- // This lets inline `Munchkin.init('302-WOS-863')` run without crashing. // The real library will overwrite this when allowed; you can replay if needed. (function () { if (!window.Munchkin) { var MK = function () {}; // placeholder MK.__otStub = true; // mark as our stub MK.__q = []; // queue MK.init = function () { MK.__q.push(["init", Array.prototype.slice.call(arguments)]); }; window.Munchkin = MK; } })(); })(); function OptanonWrapper() { } </script> <!-- OneTrust Cookies Consent Notice end for lightyear.cloud --> Lightyear Purchase Orders
Free trial

Purchase Orders: Better Spend Visibility & Stronger Controls

Lightyear’s cloud purchase order system gives you the visibility and control you need to manage spending before it happens. Easily manage who can raise POs, set approval workflows, and match them with invoices accurately.

Product Tour
🚀

Let’s Show You Around

Click to begin an interactive walkthrough

image-20260407-093340
1
Raise a purchase order
Your team can create a PO within the Lightyear system or upload through the phone/desktop app. They can select a supplier, and Lightyear auto-populates the details, keeping every order accurate from the start.
1/6
image-20260407-094933
2
Review and approve
The moment a PO lands in the approval queue, approvers are notified. They review the submission and action the request. No spreadsheets, no forwarding emails, no hold ups.
2/6
image-20260407-093551
3
Send PO to your supplier
Once approved, send the PO to your supplier directly from the Lightyear platform. You have full visibility over what was sent, to whom, and when.
3/6
image-20260407-093821
4
Mark off what's been delivered
When stock arrives, add a GRN directly against the PO and mark off individual line items as they're received. This helps you always know exactly what's been received and what's still outstanding.
4/6
image-20260407-093959
5
3-way matching
When the supplier invoice comes in, match it against your PO and GRN at the line-item level. Lightyear flags any discrepancies instantly, so you can investigate before approving payment.
5/6
image-20260407-094137
6
See your full audit trail
Every step is logged automatically with a timestamp. Search and retrieve any completed PO from the archive in seconds, giving you everything you need for audits and financial reporting.
6/6
🎉
🎉 Tour Complete!
Ready to see it in action? Book a 15-minute walkthrough, and we'll show you how Lightyear’s purchase order management works, along with loads of other new features. No commitment required.

The features that power Lightyear Purchase Orders

1. Create POs effortlessly

Define who can raise purchase orders and provide them with a clear, consistent way to do so: all in one place. Whether it's products or services, Lightyear pulls in item details directly from your suppliers' catalogues.

2. Draft or send for approval

Your team can save as a draft if not ready, or send for approval so the spend is authorised before it reaches suppliers.

3. Approve and track

Pre-defined rules automatically route the PO to the correct approver, customised based on amount, department, location, or supplier details. Approvers review POs, and the approved orders are clearly visible in the system — no more lost or untracked requests. 

4. Order and manage

Lightyear sends your purchase order directly to your supplier's email address for one-click acceptance. The right people in your team are automatically BCC'd on every order. See immediately when a supplier accepts your order request and track its status until it’s delivered.

5. Complete with full visibility

Always know what's arrived and what's still outstanding. Lightyear's Goods Received Note (GRN) feature lets you mark off individual line items as they come in, even across multiple deliveries, so nothing gets missed. Attach digital copies of your delivery dockets directly to the PO, giving you a clear audit trail whenever you need it.

Stay in control with matching and security

Match POs to invoices at the line item level. At the line item level, Lightyear matches individual lines from your purchase order to the corresponding lines on your supplier's invoice. Any discrepancies are flagged immediately, so you can see exactly where the numbers don't add up before approving payment.

Find out what Lightyear could save you

Calculate how much you could save with the perfect Lightyear plan for you. Our transparent, flexible pricing adapts based on your business needs. Unlimited users and sub-entities on every plan.

Join thousands of businesses who use Lightyear for POs

$bn+
In bills processed annually
%
Customer satisfaction rating
+
Users in 20+ countries
%
Faster payables processing

FAQs

What is a purchase order system?

A purchase order system is software that manages the end-to-end process of raising, approving, sending, and tracking purchase orders. Lightyear replaces manual, paper-based or email-driven processes with a structured, digital workflow — giving you full visibility and control over what's being ordered, by whom, and for how much, before any money leaves the business.

How does a PO system give me better control over my P&L?

A purchase order system creates a commitment record the moment an order is raised and before the invoice ever arrives. This means you can see exactly what's been committed, what's outstanding, and what's likely to hit the P&L in the coming weeks. Combined with approval controls that enforce spending limits, an effective PO system is one of the most direct levers for you to protect your profit margins. 

What are Lightyear’s purchase order system benefits?

Without a formal PO process, your business is exposed to unauthorised spending, duplicate invoices, and poor visibility over committed costs. A purchase order management system puts controls in place before spending happens. It ensures every order is approved by the right people, matched against the correct invoice, and recorded with a clear audit trail. The result is better cost control and a healthier P&L.

Can Lightyear’s ordering solution prevent unauthorised orders?

Yes, you can set up approval workflows so that every order is reviewed and authorised before it's valid, preventing anything from being committed outside of the process.

What should I look for in the best purchase order management system?

The best purchase order management system should cover the full ordering lifecycle: from PO creation and approval through to goods receipting, invoice matching, and completion. Key features to look for include configurable approval workflows, line-item level matching, supplier communication tools, spend visibility, and tight integration with your accounting software. 

Does Lightyear work for medium-sized businesses?

Yes, Lightyear is designed to be accessible for businesses of all sizes, with a straightforward onboarding process and workflows that can be as simple or as detailed as your business requires. It's easy to set up, intuitive to use, and gives you clear control over spending from day one.

How can Lightyear’s purchase order system help my team?

It reduces manual work and errors for your team. It automates approvals so the right people sign off quickly, keeping projects moving. At the same time, it gives your team full visibility of all orders, budgets, and committed spend in one place.

How do I implement Lightyear?

With Lightyear, getting your purchase order process up and running is straightforward. Set your approval workflows, define who can raise POs, and connect to your accounting software, all within a few weeks. Download our guide to learn more about getting started, or if you're ready to see it in action, book a demo with one of our team.