PageSourceSearch

https://app.getcitable.com/signin

html getcitable.com collected 2026-10-04 20:55:51 UTC 25,708 bytes, 347 lines download raw bytes

1<!DOCTYPE html><html lang="en"><head>
1<script>(function(w,i,g){w[g]=w[g]||[];if(typeof w[g].push=='function')w[g].push(i)})
2(window,'GTM-PH3XWHJ5','google_tags_first_party');</script>
2<script>(function(w,d,s,l){w[l]=w[l]||[];(function(){w[l].push(arguments);})('set', 'developer_id.dYzg1YT', true);
3		w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
4		j=d.createElement(s);j.async=true;j.src='/2j52/';
5		f.parentNode.insertBefore(j,f);
6		})(window,document,'script','dataLayer');</script>
6
7  <!-- Pre-rendered by build-pages.ts -->
8  <link rel="canonical" href="https://app.getcitable.com/signin">
9    <!--
10      Asset recovery — for the entry module and the stylesheet.
11
12      If an /assets/ chunk fails to load, nothing in the app can help: no app
13      code has run, so lib/vite-chunk-reload.ts is not installed. And the page
14      still LOOKS like a page, because build-pages.ts prerendered it.
15
16      That is what happened on 2026-08-10, twice over. A propagation gap made
17      the SPA catch-all answer the entry chunk with index.html, and Cloudflare
18      cached that HTML under the asset URL as `immutable, max-age=31536000` —
19      and, because the tags below are `crossorigin`, under the CORS cache
20      variant specifically. So `curl` got clean JS and every browser got HTML.
21      Nothing we had could see it: CI, the deploy, and verify-spa-assets.sh
22      were all green while the site was dark for every visitor at that edge.
23
24      On 2026-08-13 the same mechanism hit the STYLESHEET, and it presents
25      completely differently: React mounts, the API answers, the charts draw —
26      and the whole product paints in serif Times with no layout. It is fully
27      functional and reads as totally broken. `nosniff` on /assets/* is what
28      makes it recoverable at all: the browser refuses the mislabeled sheet
29      instead of rendering it, and fires `error` at the link, which is the hook
30      below. Note that clearing the browser cache does NOT fix this — the
31      poisoned object is at the visitor's Cloudflare PoP, not on their machine.
32
33      Reloading cannot fix it either: while `immutable` was set, browsers would
34      not revalidate even on a hard reload, and even now a reload just re-reads
35      the same poisoned object from the same edge. The only way out is a URL
36      the cache has never seen, which is what this does: on the error event,
37      re-inject the asset once with a cache-busting query. Different URL,
38      different cache key, fresh fetch — and the user never knows.
39
40      Notes:
41        - Capture phase: resource load errors do not bubble.
42        - No `crossorigin` on the retry, deliberately. Without it the request
43          is same-origin mode and sends no Origin header, so it cannot land on
44          the CORS variant that was poisoned in the first place.
45        - The stylesheet retry goes directly after the sheet it replaces, so
46          cascade order is unchanged.
47        - One shot per URL. A URL carrying `cb=` is never re-retried at the
48          asset level — but a failed retry is not ignored either, because it
49          means something worse than poisoning (below).
50        - `modulepreload` is skipped — it is only a hint, and the real module
51          tag reports its own error.
52
53      THE LAST RESORT — when the retry itself fails (2026-08-18, Misshow).
54
55      A cache-busted retry failing means the asset is not poisoned at one
56      cache key, it is GONE: this page is stale HTML naming an entry chunk
57      that no deployment serves anymore. Every /assets/ answer for it is the
58      SPA shell (or a 404), so no asset-level retry can ever succeed. A client
59      spent two days on a pixel-perfect /signin where both buttons were dead —
60      her browser held old HTML through ~40 deploys, and a Cloudflare purge
61      cannot reach a client-side cache. Switching browsers "fixed" it, which
62      is the tell: fresh HTML was always the cure.
63
64      So when a retry fails, navigate ONCE to this same page with a
65      `__fresh=` query — a URL no HTML cache has seen, hence a real fetch of
66      current HTML naming a chunk that exists. location.reload() would NOT
67      work here: it revalidates at best, and the caches that cause this
68      (client disk, China-route intermediates) serve the stale copy right
69      back. Three interlocks keep it from ever looping or misfiring:
70        - once per page lifetime (freshTried);
71        - never when `__fresh=` is already in the URL — fresh HTML that still
72          fails means the deploy itself is broken, and a loop is worse;
73        - never after the app has booted (__CITABLE_BOOTED__, set by
74          main.tsx) — a runtime lazy-chunk failure belongs to
75          lib/vite-chunk-reload.ts, and a forced navigation mid-session 
75would
76          destroy user state.
77
78      THE THIRD RUNG — a poisoned chunk the entry IMPORTS (2026-09-15, IAD).
79
80      Everything above rescues the tag that errored, which is not the same as
81      rescuing the page. A module's static imports are URLs no retry can reach:
82      `index-*.js?cb=1` still imports `./ui-vendor-*.js` — relative resolution
83      drops the query — and the browser has already memoized that URL's failure
84      for the life of the document. So when the poisoned object was a VENDOR
85      chunk, the whole ladder ran and the page stayed dead: retry, `__fresh=`,
86      the same URLs, the same HTML. Reproduced in a real browser with the old
87      guard as a control: scripts/manual-verify/poisoned-chunk-recovery.mjs.
88
89      That is #1072's deploy. Colo IAD held the shell under BOTH the entry and
90      `ui-vendor-*`; verify-spa-assets.sh passed with a warning promising that
91      visitors there "self-heal via the recovery guard"; the boot check then
92      failed 6 attempts over 300s. The promise was false, and re-running the
93      same commit could not clear it — same hashes, same cache keys.
94
95      A fresh document is the only place this can be fixed. An import map is
96      accepted only before any module has loaded, and it is the one mechanism
97      that can redirect a specifier another module hard-codes. So before the
98      `__fresh=` navigation, stash the /assets/ URLs this document NAMES — the
99      entry plus every modulepreload, which is exactly Vite's static import
100      graph. The next document remaps each to a `?cb=` twin, so the entire
101      graph is fetched under keys no cache has ever seen.
102
103      Notes:
104        - Consumed once, and ignored when older than a minute: a stale stash
105          names hashes a later deploy has already moved past.
106        - The stash is the trigger, not `__fresh=`, so the same handoff serves
107          any ladder that reloads (lib/vite-chunk-reload.ts).
108        - LIMIT: lazily-imported route chunks are not in the map, because the
109          document never names them. A poisoned route chunk stays
110          lib/vite-chunk-reload.ts's problem, not this one.
111    -->
112    
112<script>
113      (function () {
114        var STASH = 'citable:asset-bust';
115        var retried = [];
116        var freshTried = false;
117
118        // Fresh mode. A previous document died on an asset it could not retry
119        // its way out of and left the chunk list behind. Remap every one to a
120        // cache-busting twin NOW, before the parser reaches the module tags:
121        // an import map is only accepted while no module has loaded.
122        try {
123          var stash = sessionStorage.getItem(STASH);
124          if (stash) {
125            sessionStorage.removeItem(STASH);
126            var plan = JSON.parse(stash);
127            var supported = window.HTMLScriptElement
128              && HTMLScriptElement.supports
129              && HTMLScriptElement.supports('importmap');
130            if (supported && plan && plan.urls && plan.urls.length
131                && Date.now() - plan.t < 60000) {
132              var imports = {};
133              for (var i = 0; i < plan.urls.length; i++) {
134                imports[plan.urls[i]] = plan.urls[i] + '?cb=' + plan.t;
135              }
136              var map = document.createElement('script');
137              map.type = 'importmap';
138              map.textContent = JSON.stringify({ imports: imports });
139              document.head.appendChild(map);
140            }
141          }
142        } catch (e) {
143          // Storage blocked or the stash was malformed. The rungs below still
144          // work exactly as they did before.
145        }
146
147        /**
148         * Every /assets/ URL this document names: the entry module tag and
149         * Vite's modulepreload links, which together are the chunks the entry
150         * imports statically. Queries are stripped so a `cb=` retry and the
151         * original it replaced collapse to one entry.
152         */
153        function stashStaticGraph() {
154          try {
155            var urls = [];
156            var nodes = document.querySelectorAll(
157              'link[rel="modulepreload"][href], script[type="module"][src]'
158            );
159            for (var n = 0; n < nodes.length; n++) {
160              var u = (nodes[n].getAttribute('href') || nodes[n].getAttribute('src') || '').split('?')[0];
161              if (u.lastIndexOf('/assets/', 0) === 0 && urls.indexOf(u) === -1) urls.push(u);
162            }
163            if (urls.length) {
164              sessionStorage.setItem(STASH, JSON.stringify({ t: Date.now(), urls: urls }));
165            }
166          } catch (e) {
167            // No storage — the next document simply behaves as it used to.
168          }
169        }
170
171        window.addEventListener('error', function (event) {
172          var el = event.target;
173          if (!el) return;
174
175          var isStyle = el.tagName === 'LINK' && el.getAttribute('rel') === 'stylesheet';
176          if (el.tagName !== 'SCRIPT' && !isStyle) return;
177
178          var url = (isStyle ? el.getAttribute('href') : el.getAttribute('src')) || '';
179          if (url.lastIndexOf('/assets/', 0) !== 0) return;
180          if (url.indexOf('cb=') !== -1) {
181            // A retry has itself failed — the asset is gone, not poisoned.
182            // Only fresh HTML can name a chunk that exists. See header.
183            if (freshTried) return;
184            if (window.__CITABLE_BOOTED__) return;
185            var loc = window.location;
186            if ((loc.search || '').indexOf('__fresh=') !== -1) return;
187            freshTried = true;
188            stashStaticGraph();
189            loc.replace(
190              loc.pathname +
191                (loc.search ? loc.search + '&' : '?') +
192                '__fresh=' + Date.now() +
193                (loc.hash || '')
194            );
195            return;
196          }
197          if (retried.indexOf(url) !== -1) return;
198          retried.push(url);
199
200          var fresh = url + (url.indexOf('?') === -1 ? '?' : '&') + 'cb=' + Date.now();
201          if (isStyle) {
202            var sheet = document.createElement('link');
203            sheet.rel = 'stylesheet';
204            sheet.href = fresh;
205            (el.parentNode || document.head).insertBefore(sheet, el.nextSibling);
206          } else {
207            var script = document.createElement('script');
208            script.type = 'module';
209            script.src = fresh;
210            document.head.appendChild(script);
211          }
212        }, true);
213      })();
214    </script>
214
215
216    <!-- Basic Meta Tags (render-critical, must be first) -->
217    <meta charset="UTF-8">
218    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
219    <meta http-equiv="X-UA-Compatible" content="IE=edge">
220    
221    <!-- SEO Meta Tags -->
222    <title>Citable — The Autonomous Revenue Engine for Agentic Commerce</title>
223    <meta name="description" content="Citable is the autonomous revenue engine for agentic commerce. We measure how AI agents decide what shoppers buy, act on what we find, and prove the results in orders.">
224    <meta name="author" content="Citable">
225    <meta name="robots" content="index, follow">
226    
227    <!-- Open Graph / Facebook -->
228    <meta property="og:type" content="website">
229    <meta property="og:url" content="https://getcitable.com/">
230    <meta property="og:title" content="Citable — The Autonomous Revenue Engine for Agentic Commerce">
231    <meta property="og:description" content="Citable is the autonomous revenue engine for agentic commerce. We measure how AI agents decide what shoppers buy, act on what we find, and prove the results in orders.">
232    <meta property="og:image" content="https://getcitable.com/og-image-v3.jpg">
233    <meta property="og:image:width" content="1200">
234    <meta property="og:image:height" content="628">
235    <meta property="og:image:type" content="image/jpeg">
236    <meta property="og:site_name" content="Citable">
237    
238    <!-- Twitter Card -->
239    <meta name="twitter:card" content="summary_large_image">
240    <meta name="twitter:url" content="https://getcitable.com/">
241    <meta name="twitter:title" content="Citable — The Autonomous Revenue Engine for Agentic Commerce">
242    <meta name="twitter:description" content="Citable is the autonomous revenue engine for agentic commerce. We measure how AI agents decide what shoppers buy, act on what we find, and prove the results in orders.">
243    <meta name="twitter:image" content="https://getcitable.com/og-image-v3.jpg">
244    <meta name="twitter:site" content="@BeCitable">
245    <meta name="twitter:creator" content="@BeCitable">
246    
247    <!-- Security & Trust Meta Tags -->
248    <meta name="referrer" content="strict-origin-when-cross-origin">
249    <meta name="format-detection" content="telephone=no">
250    <meta http-equiv="x-dns-prefetch-control" content="on">
251    
252    <!-- Preload hero image for fast LCP -->
253    <link rel="preload" as="image" href="/Hero-V2-optimized.webp" fetchpriority="high">
254
255    <!-- Brand fonts are self-hosted via @fontsource (see frontend/src/main.tsx).
256         Eliminates render-blocking Google Fonts roundtrip + CLS from font swap. -->
257
258    <!-- Canonical URL -->
259    <!-- Favicon & App Icons -->
260    <link rel="icon" type="image/png" href="/favicon.png">
261    <link rel="apple-touch-icon" href="/favicon.png">
262    
263    <!-- Sitemap -->
264    <link rel="sitemap" type="application/xml" href="/sitemap.xml">
265    
266    <!-- Business & Contact Information (Structured Data) -->
267    
267<script type="application/ld+json">
268    {
269      "@context": "https://schema.org",
270      "@type": "SoftwareApplication",
271      "name": "Citable",
272      "applicationCategory": "BusinessApplication",
273      "offers": {
274        "@type": "AggregateOffer",
275        "lowPrice": "99",
276        "highPrice": "799",
277        "priceCurrency": "USD"
278      },
279      "operatingSystem": "Web",
280      "description": "Citable is the autonomous revenue engine for agentic commerce. We measure how AI agents decide what shoppers buy across ChatGPT, Perplexity, Gemini, Claude, Grok, and Google AI Overview, act on what we find, and prove the results in orders."
281    }
282    </script>
282
283    
284    <!-- Organization Schema -->
285    
285<script type="application/ld+json">
286    {
287      "@context": "https://schema.org",
288      "@type": "Organization",
289      "name": "Citable",
290      "url": "https://getcitable.com",
291      "logo": "https://getcitable.com/logo-black.svg",
292      "description": "The autonomous revenue engine for agentic commerce. Founded 2025, Cambridge, Massachusetts.",
293      "foundingDate": "2025",
294      "address": {
295        "@type": "PostalAddress",
296        "addressLocality": "Cambridge",
297        "addressRegion": "MA",
298        "addressCountry": "US"
299      },
300      "sameAs": [
301        "https://x.com/BeCitable",
302        "https://www.linkedin.com/company/getcitable",
303        "https://www.youtube.com/@Citable-x5n",
304        "https://www.producthunt.com/products/citable"
305      ],
306      "contactPoint": {
307        "@type": "ContactPoint",
308        "email": "[email protected]",
309        "contactType": "Customer Support",
310        "availableLanguage": "English"
311      }
312    }
313    </script>
313
314    
314<script type="module" crossorigin="" src="/assets/index-CV2ezbu5.js"></script>
314
315    <link rel="modulepreload" crossorigin="" href="/assets/react-vendor-Cak5aoPl.js">
316    <link rel="modulepreload" crossorigin="" href="/assets/utils-vendor-B9hPcH9G.js">
317    <link rel="modulepreload" crossorigin="" href="/assets/chart-vendor-C3HjQ_mn.js">
318    <link rel="modulepreload" crossorigin="" href="/assets/ui-vendor-CjS9qaFR.js">
319    <link rel="modulepreload" crossorigin="" href="/assets/animation-vendor-Cz81Kal9.js">
320    <link rel="stylesheet" crossorigin="" href="/assets/index-CuYpI8-C.css">
321  </head>
322  <body>
323    <!-- SEO-friendly content for crawlers (hidden once React loads) -->
324    <noscript>
325      <h1>Citable — The Autonomous Revenue Engine for Agentic Commerce</h1>
326      <p>Citable is the autonomous revenue engine for agentic commerce. We measure how AI agents decide what shoppers buy, act on what we find, and prove the results in orders.</p>
327    </noscript>
328    <div id="root"><div id="toast-dock"><div role="region" aria-label="Notifications (F8)" tabindex="-1" style="pointer-events: none;"><ol tabindex="-1" class="fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]"></ol></div></div><div class="min-h-screen flex flex-col"><main class="flex-1"><div class="min-h-screen flex" style="font-family: &quot;SF Pro Display&quot;, -apple-system, BlinkMacSystemFont, &quot;system-ui&quot;, sans-serif;"><div class="flex-1 min-h-screen bg-white flex items-center justify-center px-8 py-12"><div class="w-full max-w-sm"><div class="space-y-6"><div class="text-center mb-10"><img src="/logo-black.svg" alt="Citable" class="w-10 h-10 mx-auto"></div><div class="text-center space-y-1"><h1 class="text-2xl font-semibold text-gray-900 tracking-tight">Welcome back</h1><p class="text-sm text-gray-500">Sign in using Google or email</p></div><div class="space-y-3"><a href="/api/auth/google?returnUrl=%2Fdashboard" class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 border bg-background hover:text-gray-900 px-4 py-2 w-full border-gray-300 hover:bg-gray-50 text-gray-700 font-medium rounded-lg transition-all duration-200 h-11"><svg class="w-5 h-5 mr-2" viewBox="0 0 24 24"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"></path><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"></path><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"></path><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"></path></svg>Sign in with Google</a><div class="relative"><div class="absolute inset-0 flex items-center"><span class="w-full border-t border-gray-200"></span></div><div class="relative flex justify-center"><span class="bg-white px-3 text-xs text-gray-400">or</span></div></div><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 border bg-background hover:text-gray-900 px-4 py-2 w-full border-gray-300 hover:bg-gray-50 text-gray-700 font-medium rounded-lg transition-all duration-200 h-11" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mail w-5 h-5 mr-2 text-gray-500"><rect width="20" height="16" x="2" y="4" rx="2"></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path></svg>Sign in with email</button><div class="text-center pt-1"><p class="text-sm text-gray-600">Don't have an account? <button type="button" class="text-gray-900 underline font-normal hover:text-gray-700 transition-colors">Sign up</button></p></div></div></div></div></div><div class="hidden lg:block w-px bg-gray-200"></div><div class="hidden lg:flex flex-col w-1/2 min-h-screen px-10 py-10" style="background-color: rgb(242, 241, 237);"><div class="flex-1 flex flex-col justify-center gap-6"><div class="w-full flex flex-col gap-3"><div class="relative overflow-hidden rounded-2xl shadow-md bg-white" style="cursor: grab;"><div class="flex" draggable="false" style="width: 2240px; user-select: none; touch-action: pan-y; transform: none;"><div style="width: 560px; flex-shrink: 0;"><img src="/%5BInside%20Citable%5D%20Blog%20Generator.png" alt="Publish AI-cited blog posts that get found by ChatGPT &amp; Perplexity" class="w-full h-auto block select-none" draggable="false"></div><div style="width: 560px; flex-shrink: 0;"><img src="/%5BInside%20Citable%5D%20Reddit%20Growth%20Assistant.png" alt="Grow your Reddit presence authentically — without risking a ban" class="w-full h-auto block select-none" draggable="false"></div><div style="width: 560px; flex-shrink: 0;"><img src="/%5BInside%20Citable%5D%20Youtube%20Video%20Generator.png" alt="Go from brand idea to published YouTube video in under a minute" class="w-full h-auto block select-none" draggable="false"></div><div style="width: 560px; flex-shrink: 0;"><img src="/%5BInside%20Citable%5D%20AI%20Action%20Engine.png" alt="Your personal AI growth expert that takes action — so you don't have to" class="w-full h-auto block select-none" draggable="false"></div></div></div><div class="flex justify-center items-center gap-2"><button aria-label="Go to slide 1" class="h-1.5 rounded-full transition-all duration-300 focus:outline-none" style="width: 28px; background-color: rgb(31, 41, 55);"></button><button aria-label="Go to slide 2" class="h-1.5 rounded-full transition-all duration-300 focus:outline-none" style="width: 8px; background-color: rgb(200, 199, 195);"></button><button aria-label="Go to slide 3" class="h-1.5 rounded-full transition-all duration-300 focus:outline-none" style="width: 8px; background-color: rgb(200, 199, 195);"></button><button aria-label="Go to slide 4" class="h-1.5 rounded-full transition-all duration-300 focus:outline-none" style="width: 8px; background-color: rgb(200, 199, 195);"></button></div><p class="text-center text-xs text-gray-500 leading-snug px-2">Publish AI-cited blog posts that get found by ChatGPT &amp; Perplexity</p><div class="grid grid-cols-4 gap-3 mt-1"><button class="rounded-xl p-3 flex flex-col gap-1 text-left transition-all duration-200 focus:outline-none" style="background-color: rgb(232, 231, 227);"><p class="text-12 font-semibold tracking-widest uppercase leading-tight text-gray-400">AI VISIBILITY UPLIFT</p><p class="text-lg font-bold leading-tight transition-colors duration-300" style="color: rgb(90, 143, 114);">0% → 8%</p></button><button class="rounded-xl p-3 flex flex-col gap-1 text-left transition-all duration-200 focus:outline-none" style="background-color: rgb(232, 231, 227);"><p class="text-12 font-semibold tracking-widest uppercase leading-tight text-gray-400">RANKING</p><p class="text-lg font-bold leading-tight transition-colors duration-300" style="color: rgb(31, 41, 55);">#1</p></button><button class="rounded-xl p-3 flex flex-col gap-1 text-left transition-all duration-200 focus:outline-none" style="background-color: rgb(232, 231, 227);"><p class="text-12 font-semibold tracking-widest uppercase leading-tight text-gray-400">HOURS SAVED</p><p class="text-lg font-bold leading-tight transition-colors duration-300" style="color: rgb(31, 41, 55);">20+</p></button><button class="rounded-xl p-3 flex flex-col gap-1 text-left transition-all duration-200 focus:outline-none" style="background-color: rgb(232, 231, 227);"><p class="text-12 font-semibold tracking-widest uppercase leading-tight text-gray-400">AWARENESS</p><p class="text-lg font-bold leading-tight transition-colors duration-300" style="color: rgb(31, 41, 55);">500,000+</p></button></div></div></div></div></div></main></div></div>
329
330    <!--
331      No trackers in this file. Nothing in it can read VITE_ANALYTICS, and Vite
332      serves it as it is in dev and in the e2e suite, so a tag pasted here
333      reports from every local session and every e2e run into the real
334      accounts. The Google tag, the Meta pixel, the OpenAI pixel, PostHog and
335      Clarity load from src/lib/, in the production build only. GTM is gone:
336      GTM-PH3XWHJ5 publishes no tags, and in production Cloudflare's Google tag
337      gateway (/2j52/) loads it first-party on every page anyway.
338      Pinned by frontend/tests/index-html-loads-no-trackers.test.ts.
339    -->
340
341    <!-- DNS Prefetch for deferred third-party scripts -->
342    <link rel="dns-prefetch" href="https://www.googletagmanager.com">
343    <link rel="dns-prefetch" href="https://www.google-analytics.com">
344    <link rel="dns-prefetch" href="https://js.stripe.com">
345  
346<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"c5c5699a9bce4190bdf6541584b62159","r":1,"spa":2}' crossorigin="anonymous"></script>
346
347</body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.