Atharva Unde
~/projects/ takeoutlens
Open Source ProductPersonal ProjectCompletedQ3 2026

TakeoutLens

Self-hosted Google Takeout viewer - browse a full export of mail, chat, calendar and Drive in your browser, with nothing leaving your machine.

RESULTMail, chat, calendar and Drive from a full Takeout, searchable locally with nothing leaving your machine
ROLESole developer - product spec, indexer, backend, frontend, Docker packaging
TIMELINEQ3 2026 · Personal Project
TakeoutLens screenshot 1
01 / 12
01 · THE PROBLEM

Google Takeout hands you a complete copy of your data - and then leaves you with a pile of files. A huge .mbox mail archive, .vcf contacts, per-conversation Chat JSON with thousands of attachments, .ics calendars, Keep notes, and a sprawling Drive folder. The data is legally yours and practically unreadable.

Even a single account's export is huge and mostly media. Existing viewers only cover one product each (an mbox reader, a Chat reader, a Photos gallery), and the commercial ones are closed and Windows-oriented. Nothing covered mail, chat, calendar and Drive together, self-hosted, without uploading personal data to someone else's server.


02 · THE SOLUTION

TakeoutLens is a Next.js + shadcn/ui web app shipped as a Docker image. Extract your Takeout, mount it read-only into the container, open localhost, and browse it like the products it came from: a mail client, a chat timeline, a calendar, a file browser.

The result: a full mailbox and years of chat history become searchable in the browser without loading a large file into memory, without modifying the export, and without a single outbound network call.


03 · KEY FEATURES

9 things it does well

MailLabels, threads, sanitized HTML bodies, inline images, attachments, .eml export and full-text search with label: / has:attachment filters

04 · TECHNICAL ARCHITECTURE

How it fits together

Next.js 16React 19shadcn/uiTanStack TableZustandSQLite (better-sqlite3, FTS5)sharpVitestPlaywrightDocker
ALSONext.js 16 App Router + shadcn/uiSeparate Node indexer processSQLite (WAL) + FTS5 full-text searchOffset-indexed mbox with ranged readsRange-capable file routes (media, thumb, download)Read-only Takeout mount + writable data volumeDocker (localhost-only) or native pnpm
DATA FLOW

A separate indexer process streams the Takeout tree and writes a SQLite database into a writable /data volume; the Takeout itself is mounted read-only at /takeout. The web server only reads that index. Pages are Server Components, interactive reads (search, pagination) are Server Functions, and media is served through three Range-capable route handlers addressed by opaque IDs - the browser never sends a filesystem path.

KEY DESIGN DECISIONS
DECISION 01Offset-indexed mail, not copied mail

The indexer makes one streaming pass over the mbox and stores each message's byte offset and length plus headers, labels, thread ID and a snippet. Full bodies and attachments are parsed on demand with a ranged read at view time. /data stays small and the mbox remains the source of truth.

05 · DEVELOPMENT PROCESS

6 phases

Wrote the intent, then a spec grounded in the real export's shapes (Chat date format with U+202F, mbox counts, Photos sidecar naming) before any code
06 · QUICK START

Quick Start

bash
# extract your Takeout first, then:TAKEOUT_DIR=~/Takeout docker compose up

Open http://localhost:3000, set a password on first run, and start browsing. The Takeout folder is mounted read-only; the index lives in a separate volume.


07 · IMPACT & TAKEAWAY
Your Google data, readable again - a full Takeout browsed like the original products, self-hosted, read-only, and nothing leaves your machine.

A full Takeout goes from unreadable archive to something you can actually search and read, on your own machine. The spike measurements shaped the design more than the plan did: indexer memory came out above the original target, and the long chat timeline needed windowing rather than one giant scroller - both were caught by measuring real data early instead of assuming.


Google Takeout viewerself-hostedopen sourceNext.jsshadcn/uiSQLiteFTS5mbox viewerDockerprivacydata exportGoogle Chat export
KEEP EXPLORINGAll projects