Spotify Wrapped, but for YouTube. Drop your watch-history.json and get a personal report: years of viewing trends, a daily heatmap, top channels (all-time and last 90 days), most-rewatched videos, hour-of-day patterns, streaks. All of it rendered in your browser — or in your terminal — without a single network request.
There's a web app (drag-and-drop, dark themed) and a Deno CLI that prints the same stats as ASCII.
This is the whole pitch:
- No server. The web app is static HTML/CSS/JS.
- No telemetry, no analytics, no cookies, no CDN fonts.
- No network requests by default while the app runs — open the Network tab and watch. The one exception is opt-in: flip the Thumbnails switch in the report header and channel avatars hotlink
i.ytimg.com(no API, no key — just images). - Parsing happens locally via the browser's File API.
- Refresh = gone. Nothing is persisted (toggle preference excepted, in
localStorage).
By default channel avatars are deterministic gradients hashed from the channel name.
- Sign in to Google Takeout.
- Deselect all, then tick only YouTube and YouTube Music.
- Click All YouTube data included → Deselect all → tick history → choose JSON (not HTML).
- Create the export, wait for the email, download and unzip.
- The file lives at
Takeout/YouTube and YouTube Music/history/watch-history.json.
The web app has the same walkthrough at /about.html#takeout.
Hosted at yt-stats.rix1.dev. To run it locally:
python3 -m http.server 4173
# open http://localhost:4173Drop your watch-history.json on the page — or click See an example report to load a 500-entry 2022 sample without uploading anything. The report renders in a few hundred ms.
Requires Deno (tested on 2.7+).
deno run --allow-read yt-stats.ts watch-history.jsonOr make it executable:
chmod +x yt-stats.ts
./yt-stats.ts watch-history.json- Total watches, year range, unique channels, unique videos
- Year × month grid
- Daily heatmap (last 53 weeks, GitHub-style)
- Hour-of-day × day-of-week matrix
- Top channels (all-time and last 90 days)
- Most-rewatched videos
- Play-count distribution (1, 2, 3–5, 6–10, …, 51+)
- Longest watching streak
Times are local. Ads, posts, and YouTube Music entries are filtered out.
core.js Pure stats engine — runs in Deno and the browser
cli.js ANSI/ASCII renderer for the terminal
yt-stats.ts Deno entry point (7 lines, wires core + cli)
index.html Static web app — landing + report
about.html Privacy and Takeout walkthrough
app.js Browser renderer — DOM, drag-and-drop, master-detail
styles.css Dark theme
example.json Stride-sampled 2022 subset used by "See an example"
core.js has no dependencies and no I/O. cli.js writes ANSI to stdout. app.js renders into the DOM. Swap renderers freely.
Everything lives at the repo root so GitHub Pages can serve it directly.
MIT.
