1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <meta name="theme-color" content="#1E40AF" /> 7 8 <title>Privacy Policy: Tokdash</title> 9 <meta name="description" content="Privacy policy for Tokdash Companion (the desktop tray/menu-bar app) and for the tokdash.github.io website. Covers what data each one collects, and what it does not." /> 10 11 <link rel="icon" href="/static/icons/icon-192.png" sizes="192x192" /> 12 <link rel="canonical" href="https://tokdash.github.io/privacy/" /> 13 14 <!-- Open Graph --> 15 <meta property="og:type" content="website" /> 16 <meta property="og:title" content="Privacy Policy: Tokdash" /> 17 <meta property="og:description" content="What Tokdash Companion collects (nothing) and what tokdash.github.io collects (standard website analytics)." /> 18 <meta property="og:url" content="https://tokdash.github.io/privacy/" /> 19 <meta property="og:image" content="https://tokdash.github.io/static/icons/icon-512.png" /> 20 <meta name="twitter:card" content="summary_large_image" /> 21 22 <!-- Fonts (Design System: Fira Code / Fira Sans) --> 23 <link rel="preconnect" href="https://fonts.googleapis.com" /> 24 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 25 <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&family=Fira+Sans:wght@300;400;500;600;700&display=swap" rel="stylesheet" /> 26 27 <!-- Tailwind: prebuilt static CSS shared with the rest of the site --> 28 <link rel="stylesheet" href="/static/landing.css" /> 29 30 <!-- Avoid theme flash: set the class before paint (mirrors index.html) --> 31
31<script> 32 (function () { 33 document.documentElement.classList.add('js'); 34 try { 35 var saved = localStorage.getItem('tokdash-site-theme'); 36 var dark = saved ? saved === 'dark' 37 : (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches); 38 if (dark) document.documentElement.classList.add('dark'); 39 } catch (e) {} 40 })(); 41 </script>
41 42 43 <style> 44 /* ---- Design tokens (mirrored from index.html) ---- */ 45 :root { 46 --color-primary: #1E40AF; 47 --color-secondary: #3B82F6; 48 --color-cta: #F59E0B; 49 --color-bg: #F8FAFC; 50 --color-text: #0F172A; 51 --color-muted: #475569; 52 --color-border: #E2E8F0; 53 --color-cost: #0F766E; 54 --radius-md: 12px; 55 --radius-lg: 16px; 56 --t-fast: 180ms; 57 --shadow-sm: 0 1px 2px rgba(0,0,0,0.05); 58 --shadow-md: 0 8px 24px rgba(15, 23, 42, 0.08); 59 } 60 61 /* ---- Lenis smooth scroll ---- */ 62 html.lenis, html.lenis body { height: auto; } 63 html, html.lenis { scroll-behavior: auto !important; } 64 .lenis.lenis-smooth { scroll-behavior: auto !important; } 65 .lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; } 66 .lenis.lenis-stopped { overflow: clip; } 67 .lenis.lenis-smooth iframe { pointer-events: none; } 68 header, .card { 69 transform: translateZ(0); 70 -webkit-transform: translateZ(0); 71 } 72 html.dark { 73 --color-primary: #60A5FA; 74 --color-secondary: #93C5FD; 75 --color-cta: #FBBF24; 76 --color-bg: #0F172A; 77 --color-text: #E2E8F0; 78 --color-muted: #94A3B8; 79 --color-border: #334155; 80 --color-cost: #34D399; 81 --shadow-sm: 0 1px 2px rgba(0,0,0,0.4); 82 --shadow-md: 0 8px 24px rgba(0,0,0,0.4); 83 } 84 85 html, body { min-height: 100%; overflow-x: clip; } 86 html { scroll-behavior: smooth; } 87 88 body { 89 font-family: "Fira Sans", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, "Noto Sans"; 90 background: radial-gradient(1200px 600px at 20% -10%, rgba(59,130,246,0.16), transparent 65%), 91 radial-gradient(900px 600px at 90% 10%, rgba(245,158,11,0.12), transparent 55%), 92 var(--color-bg); 93 color: var(--color-text); 94 -webkit-font-smoothing: antialiased; 95 } 96 html.dark body { 97 background: radial-gradient(1200px 600px at 20% -10%, rgba(59,130,246,0.10), transparent 65%), 98 radial-gradient(900px 600px at 90% 10%, rgba(245,158,11,0.06), transparent 55%), 99 var(--color-bg); 100 } 101 102 .mono { font-family: "Fira Code", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; } 103 .text-muted { color: var(--color-muted); } 104 105 .surface { 106 background: rgba(255, 255, 255, 0.95); 107 border: 1px solid var(--color-border); 108 border-radius: var(--radius-lg); 109 box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06); 110 } 111 html.dark .surface {
112 background: rgba(30, 41, 59, 0.9); 113 border-color: #334155; 114 box-shadow: 0 4px 6px -1px rgba(0,0,0,0.3), 0 2px 4px -1px rgba(0,0,0,0.2); 115 } 116 117 .btn { 118 display: inline-flex; align-items: center; justify-content: center; gap: 10px; 119 border-radius: 10px; padding: 12px 18px; min-height: 48px; 120 font-weight: 600; cursor: pointer; user-select: none; white-space: nowrap; 121 transition: transform var(--t-fast) ease, box-shadow var(--t-fast) ease, background var(--t-fast) ease, border-color var(--t-fast) ease; 122 text-decoration: none; 123 } 124 .btn-ghost { 125 background: rgba(15, 23, 42, 0.04); color: var(--color-text); 126 border: 1px solid rgba(226,232,240,0.9); 127 } 128 .btn-ghost:hover { background: rgba(15, 23, 42, 0.08); transform: translateY(-1px); border-color: rgba(30,64,175,0.3); } 129 html.dark .btn-ghost { background: rgba(148,163,184,0.08); border-color: #475569; } 130 html.dark .btn-ghost:hover { background: rgba(148,163,184,0.15); border-color: rgba(96,165,250,0.4); } 131 132 .site-nav { 133 position: sticky; top: 0; z-index: 50; 134 backdrop-filter: blur(14px); 135 background: color-mix(in srgb, var(--color-bg) 78%, transparent); 136 border-bottom: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent); 137 } 138 .nav-link { 139 font-size: 14px; font-weight: 600; color: var(--color-muted); 140 padding: 8px 12px; border-radius: 8px; transition: color var(--t-fast) ease, background var(--t-fast) ease; 141 } 142 .nav-link:hover { color: var(--color-text); background: rgba(30,64,175,0.06); } 143 144 .divider-grad { height: 1px; background: linear-gradient(90deg, transparent, var(--color-border), transparent); } 145 146 .chip { 147 display: inline-flex; align-items: center; gap: 8px; 148 padding: 6px 14px; border-radius: 999px; font-size: 12.5px; font-weight: 600; 149 letter-spacing: 0.02em; color: var(--color-primary); 150 background: color-mix(in srgb, var(--color-primary) 10%, transparent); 151 border: 1px solid color-mix(in srgb, var(--color-primary) 24%, transparent); 152 } 153 154 /* ---- Policy article typography (page-local; not part of shared landing.css) ---- */ 155 .policy h2 { 156 font-size: 1.35rem; font-weight: 800; letter-spacing: -0.01em; 157 margin-top: 2.5rem; padding-top: 1.5rem; 158 border-top: 1px solid var(--color-border); 159 } 160 .policy h2:first-of-type { margin-top: 0; padding-top: 0; border-top: none; } 161 .policy p { margin-top: 0.9rem; line-height: 1.7; color: var(--color-text); } 162 .policy p.lede { color: var(--color-muted); } 163 .policy ul { margin-top: 0.9rem; padding-left: 1.25rem; line-height: 1.7; } 164 .policy li { list-style: disc; margin-top: 0.4rem; } 165 .policy li::marker { color: var(--color-primary); } 166 .policy a { color: var(--color-primary); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; } 167 .policy code { 168 font-family: "Fira Code", monospace; font-size: 0.9em; 169 background: color-mix(in srgb, var(--color-border) 45%, transparent); 170 padding: 0.15em 0.4em; border-radius: 5px; 171 } 172 .policy strong { font-weight: 700; } 173 174 .callout { 175 border-radius: var(--radius-md); 176 border: 1px solid color-mix(in srgb, var(--color-primary) 26%, var(--color-border)); 177 background: color-mix(in srgb, var(--color-primary) 7%, transparent); 178 padding: 1.1rem 1.25rem; 179 margin-top: 1.5rem; 180 } 181 .callout p { margin-top: 0; } 182 .callout p + p { margin-top: 0.6rem; } 183 184 .callout-amber { 185 border-color: color-mix(in srgb, var(--color-cta) 34%, var(--color-border)); 186 background: color-mix(in srgb, var(--color-cta) 9%, transparent); 187 } 188 </style> 189</head> 190<body> 191 192 <header class="site-nav"> 193 <div class="max-w-[1180px] mx-auto px-4 sm:px-6 h-16 flex items-center justify-between gap-4"> 194 <a href="/" class="flex items-center gap-2.5 shrink-0"> 195 <img src="/static/icons/logo.png" alt="Tokdash logo" width="32" height="32" style="width:32px;height:32px;object-fit:contain;" /> 196 <span class="mono text-lg font-extrabold tracking-tight">Tokdash</span> 197 </a> 198 <div class="flex items-center gap-2"> 199 <button id="themeToggle" class="btn btn-ghost" style="min-height:40px;padding:8px 10px;" aria-label="Toggle dark mode"> 200 <svg id="iconMoon" width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> 201 <svg id="iconSun" width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true" style="display:none;"><circle cx="12" cy="12" r="5" stroke="currentColor" stroke-width="2"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg> 202 </button> 203 <a href="/demo/" class="nav-link">Live demo</a> 204 <a href="/" class="nav-link">
204â Home</a> 205 </div> 206 </div> 207 </header> 208 209 <main> 210 <section class="max-w-3xl mx-auto px-4 sm:px-6 pt-12 pb-4"> 211 <span class="chip"><span class="dot" style="width:7px;height:7px;border-radius:50%;background:var(--color-cta);display:inline-block;"></span> Privacy policy</span> 212 <h1 class="text-3xl sm:text-4xl font-extrabold tracking-tight mt-4">Tokdash privacy policy</h1> 213 <p class="text-muted mt-3"> 214 This page covers two different things: the <strong>Tokdash Companion</strong> desktop 215 app (Microsoft Store and portable builds), and <strong>this website</strong> 216 (tokdash.github.io). They behave differently, so each gets its own section below: 217 read the heading before assuming a claim applies to both. 218 </p> 219 <p class="text-xs text-muted mt-4">Last updated: 2026-08-18</p> 220 </section> 221 222 <div class="max-w-3xl mx-auto px-4 sm:px-6"><div class="divider-grad"></div></div> 223 224 <section class="max-w-3xl mx-auto px-4 sm:px-6 py-10"> 225 <article class="policy surface" style="padding: 2rem;"> 226 227 <h2>What Tokdash Companion is</h2> 228 <p> 229 Tokdash Companion is a notification-area (system tray) client for Tokdash, a 230 service you run on your own machine or on a machine you control. The companion 231 displays usage and quota figures that the Tokdash service reports. It is a 232 viewer; it does not itself gather usage data. 233 </p> 234 235 <h2>Data collected by the app</h2> 236 <p> 237 <strong>None.</strong> Tokdash Companion collects no personal information, sends 238 no analytics or telemetry, and has no server component operated by the 239 developer. 240 </p> 241 242 <h2>Data stored on your device</h2> 243 <p> 244 Your settings, including server addresses and labels, notification thresholds, language, 245 launch-at-login preference, and update-check preference, are stored on your 246 device. In the Microsoft Store build they live in the app's own package storage 247 and are removed when you uninstall the app. 248 </p> 249 <p> 250 Usage and quota figures are held in memory while the app is running and are not 251 written to disk. 252 </p> 253 254 <h2>Network connections the app makes</h2> 255 <p>Tokdash Companion connects only to:</p> 256 <ul> 257 <li> 258 <strong>The Tokdash server addresses you configure.</strong> The default is 259 <code>http://127.0.0.1:55423</code> on your own machine. If you add another 260 address, the companion connects to that one too. It connects to nothing you 261 have not entered. 262 </li> 263 <li> 264 <strong>GitHub's public releases API</strong>, only in the portable 265 (non-Store) build, and only if you turn update checking on. It is off by 266 default. The request is unauthenticated and sends no information about you or 267 your usage. <strong>The Microsoft Store build never contacts GitHub</strong>; 268 the Store delivers updates instead. 269 </li> 270 </ul> 271 <p>No data is sent to the developer.</p> 272 273 <h2>What the app does not do</h2> 274 <p> 275 It does not read browser data, credential stores, or session files. It does not 276 scan your network or enumerate ports. It does not run background services 277 beyond its own tray process, and it does not install or download additional 278 software. 279 </p> 280 281 <h2>Permissions</h2> 282 <p> 283 The app runs as a full-trust desktop application (<code>runFullTrust</code>). 284 This is what a packaged WPF desktop application requires; it is not used to 285 access anything described above as out of scope. 286 </p> 287 288 <h2>Website analytics</h2> 289 <p class="lede"> 290 This section is about <strong>tokdash.github.io, the website rather than the app.</strong> 291 Nothing in this section applies to Tokdash Companion or to the Tokdash server; 292 those remain exactly as described above: no telemetry, no accounts, no 293 phone-home. 294 </p> 295 <p> 296 This website uses <strong>Google Analytics</strong> to understand how visitors 297 use the site. Google Analytics sets cookies in your browser and collects
298 standard web-analytics data such as the pages you visit, approximate location 299 (derived from IP address), and your browser and device type. This data is 300 processed by Google; see 301 <a href="https://policies.google.com/privacy" target="_blank" rel="noopener">Google's Privacy Policy</a> 302 for how Google handles it. You can limit this via your browser's cookie 303 settings, tracking-protection features, or an ad/tracker blocker. 304 </p> 305 <div class="callout callout-amber"> 306 <p> 307 <strong>Why the split.</strong> The Tokdash <em>app</em> is local-first and 308 collects nothing. The Tokdash <em>website</em>, including the marketing pages and demo 309 you may have arrived from, runs standard Google Analytics like most websites 310 do. Those are two different pieces of software with two different privacy 311 postures; this page states both plainly instead of letting one claim be read 312 as covering the other. 313 </p> 314 </div> 315 316 <h2>Children</h2> 317 <p>The app is not directed at children and collects no information from anyone.</p> 318 319 <h2>Changes to this policy</h2> 320 <p>Material changes to this policy will be published at this URL with an updated date.</p> 321 322 <h2>Contact</h2> 323 <p> 324 Open an issue at 325 <a href="https://github.com/JingbiaoMei/Tokdash/issues" target="_blank" rel="noopener">github.com/JingbiaoMei/Tokdash/issues</a>. 326 </p> 327 328 </article> 329 330 <p class="text-center mt-8"> 331 <a href="/" class="btn btn-ghost">â Back to the Tokdash homepage</a> 332 </p> 333 </section> 334 </main> 335 336 <footer class="border-t" style="border-color: color-mix(in srgb, var(--color-border) 70%, transparent);"> 337 <div class="max-w-[1180px] mx-auto px-4 sm:px-6 py-10 flex flex-col sm:flex-row items-center justify-between gap-6"> 338 <div class="flex items-center gap-2.5"> 339 <img src="/static/icons/logo.png" alt="" width="26" height="26" style="width:26px;height:26px;object-fit:contain;" /> 340 <div> 341 <div class="mono font-extrabold leading-tight">Tokdash</div> 342 <div class="text-xs text-muted">Local token & cost dashboard · MIT</div> 343 </div> 344 </div> 345 <nav class="flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-sm" aria-label="Footer"> 346 <a href="/demo/" class="nav-link" style="padding:6px 0;">Live demo</a> 347 <a href="https://github.com/JingbiaoMei/Tokdash" target="_blank" rel="noopener" class="nav-link" style="padding:6px 0;">GitHub</a> 348 <a href="https://github.com/JingbiaoMei/Tokdash/blob/main/LICENSE" target="_blank" rel="noopener" class="nav-link" style="padding:6px 0;">License</a> 349 </nav> 350 </div> 351 </footer> 352 353
353<script> 354 // ---- Theme toggle (mirrors index.html) ---- 355 (function () { 356 var root = document.documentElement; 357 var moon = document.getElementById('iconMoon'); 358 var sun = document.getElementById('iconSun'); 359 function sync() { 360 var dark = root.classList.contains('dark'); 361 moon.style.display = dark ? 'none' : 'block'; 362 sun.style.display = dark ? 'block' : 'none'; 363 } 364 sync(); 365 document.getElementById('themeToggle').addEventListener('click', function () { 366 root.classList.toggle('dark'); 367 try { localStorage.setItem('tokdash-site-theme', root.classList.contains('dark') ? 'dark' : 'light'); } catch (e) {} 368 sync(); 369 }); 370 })(); 371 </script>
371 372 373 <!-- Lenis Smooth Scrolling --> 374
374<script src="/static/lenis.min.js"></script>
374 375
375<script> 376 (function () { 377 if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; 378 if (typeof Lenis === 'undefined') return; 379 var lenis = new Lenis({ 380 lerp: 0.12, 381 wheelMultiplier: 1.0, 382 touchMultiplier: 1.5, 383 smoothWheel: true, 384 }); 385 function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } 386 requestAnimationFrame(raf); 387 window.__lenis = lenis; 388 })(); 389 </script>
389 390</body> 391</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.