From 2b3f9d5d7468407b7865a71e057c049fb81522cf Mon Sep 17 00:00:00 2001 From: andrewleesteele <8799863+andrewleesteele@users.noreply.github.com> Date: Sat, 5 Sep 2026 18:53:40 +0000 Subject: [PATCH 1/2] Add consent-gated Conceptual Analytics pixel to docs Mintlify loads every .js file in the content directory on every page, which is how the pixel reaches docs pages that the marketing site's layout never renders. The docs are served under www.kernel.sh/docs, so the c15t consent cookie set on the marketing site is readable here and gates the pixel the same way. respectDNT and anonymizeIP are off in the shipped pixel config and are turned on before the loader runs. The pixel has no router hooks, so docs navigation sends its own page_view. Co-Authored-By: Claude Opus 5 --- conceptual.js | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 conceptual.js diff --git a/conceptual.js b/conceptual.js new file mode 100644 index 0000000..98e59e0 --- /dev/null +++ b/conceptual.js @@ -0,0 +1,84 @@ +/* + * Conceptual Analytics pixel. + * + * Mintlify loads every .js file in this directory on every docs page. The docs + * are served under www.kernel.sh/docs via a rewrite from the marketing site, so + * the c15t consent cookie the marketing site sets is readable here and the two + * halves of the origin share one consent decision. + */ +(function () { + var CONSENT_CATEGORY = "marketing"; + var PIXEL_KEY = + "acfc03eea265bec68ec3dfb5bc9f1bf6cda7644ceed3260980286b6f0b4098a3"; + var LOADER_SRC = + "https://plfalg.kernel.sh/analytics/loader-v1.js?key=" + + encodeURIComponent(PIXEL_KEY) + + "&v=1.1.0"; + + function hasConsent() { + try { + var cookie = document.cookie.match(/(?:^|;\s*)c15t=([^;]*)/); + if (cookie && cookie[1]) { + return cookie[1].indexOf("c." + CONSENT_CATEGORY + ":1") !== -1; + } + } catch (e) {} + + try { + var raw = localStorage.getItem("c15t"); + if (raw) { + var parsed = JSON.parse(raw); + return !!(parsed && parsed.consents && parsed.consents[CONSENT_CATEGORY]); + } + } catch (e) {} + + return false; + } + + function load() { + if (window.ca) return; + + // measure-v1.js reads __CA_CONFIG once at init, so it has to be set before + // the loader injects it. Both flags are off in the shipped pixel config. + window.__CA_CONFIG = window.__CA_CONFIG || {}; + window.__CA_CONFIG.respectDNT = true; + window.__CA_CONFIG.anonymizeIP = true; + + window.ca = function () { + (window.ca.q = window.ca.q || []).push(arguments); + }; + + var script = document.createElement("script"); + script.async = true; + script.src = LOADER_SRC; + document.head.appendChild(script); + } + + // The pixel sends one page_view on init and has no router hooks, so docs + // navigation between pages is invisible unless we send it ourselves. + function trackNavigations() { + var lastPath = location.pathname + location.search; + + function onNavigate() { + var path = location.pathname + location.search; + if (path === lastPath) return; + lastPath = path; + if (window.ca) window.ca("track", "page_view"); + } + + ["pushState", "replaceState"].forEach(function (method) { + var original = history[method]; + history[method] = function () { + var result = original.apply(this, arguments); + onNavigate(); + return result; + }; + }); + + window.addEventListener("popstate", onNavigate); + } + + if (!hasConsent()) return; + + load(); + trackNavigations(); +})(); From 05231c24bcb6f92a04b997ff20505ec63a8c7d12 Mon Sep 17 00:00:00 2001 From: andrewleesteele <8799863+andrewleesteele@users.noreply.github.com> Date: Sat, 5 Sep 2026 19:05:18 +0000 Subject: [PATCH 2/2] Geo-gate the docs pixel instead of requiring a stored consent decision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The consent banner lives in the marketing site's app and never renders on a docs page, so a visitor whose first page is a docs page had no way to reach a decision and never got the pixel — which is most of the traffic this is meant to cover. An existing decision still wins. Absent one, ask the same c15t endpoint the marketing site uses and apply its rule: prompt in regulated jurisdictions, auto-grant elsewhere. The endpoint is same-origin here. Any failure leaves the pixel unloaded. --- conceptual.js | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/conceptual.js b/conceptual.js index 98e59e0..f5be2e5 100644 --- a/conceptual.js +++ b/conceptual.js @@ -3,8 +3,8 @@ * * Mintlify loads every .js file in this directory on every docs page. The docs * are served under www.kernel.sh/docs via a rewrite from the marketing site, so - * the c15t consent cookie the marketing site sets is readable here and the two - * halves of the origin share one consent decision. + * both the c15t consent cookie and the c15t API are same-origin here and the + * two halves of the site can share one consent decision. */ (function () { var CONSENT_CATEGORY = "marketing"; @@ -14,12 +14,15 @@ "https://plfalg.kernel.sh/analytics/loader-v1.js?key=" + encodeURIComponent(PIXEL_KEY) + "&v=1.1.0"; + var JURISDICTION_URL = "/api/c15t/show-consent-banner"; - function hasConsent() { + // true granted, false declined, null no decision recorded yet. + function storedConsent() { try { var cookie = document.cookie.match(/(?:^|;\s*)c15t=([^;]*)/); if (cookie && cookie[1]) { - return cookie[1].indexOf("c." + CONSENT_CATEGORY + ":1") !== -1; + if (cookie[1].indexOf("c." + CONSENT_CATEGORY + ":1") !== -1) return true; + if (cookie[1].indexOf("c." + CONSENT_CATEGORY + ":0") !== -1) return false; } } catch (e) {} @@ -27,11 +30,14 @@ var raw = localStorage.getItem("c15t"); if (raw) { var parsed = JSON.parse(raw); - return !!(parsed && parsed.consents && parsed.consents[CONSENT_CATEGORY]); + var consents = parsed && parsed.consents; + if (consents && typeof consents[CONSENT_CATEGORY] === "boolean") { + return consents[CONSENT_CATEGORY]; + } } } catch (e) {} - return false; + return null; } function load() { @@ -77,8 +83,28 @@ window.addEventListener("popstate", onNavigate); } - if (!hasConsent()) return; + function start() { + load(); + trackNavigations(); + } + + var stored = storedConsent(); + if (stored !== null) { + if (stored) start(); + return; + } - load(); - trackNavigations(); + // Nobody has decided yet, which is the normal case for a visitor whose first + // page is a docs page — the consent banner lives in the marketing site's app + // and never renders here. Apply the same rule c15t applies there: it only + // prompts in regulated jurisdictions and auto-grants everywhere else. Any + // failure leaves the pixel unloaded. + fetch(JURISDICTION_URL, { credentials: "same-origin" }) + .then(function (response) { + return response.ok ? response.json() : null; + }) + .then(function (data) { + if (data && data.showConsentBanner === false) start(); + }) + .catch(function () {}); })();