Analyze focal length and aperture stats from your photo library. Look back at what you actually shoot.
Prerequisites: Node.js 20+ (nvm use will pick up the .nvmrc) and exiftool.
brew install exiftool # macOS
nvm use # optional, ensures correct Node version
npm install
npm linkloupe [path] [options]Arguments
| Argument | Description |
|---|---|
path |
Directory to scan, or .photoslibrary path (defaults to .) |
Options
| Option | Description |
|---|---|
--json |
Output as JSON |
--csv |
Output as CSV to stdout |
--output, -o |
Write CSV to file |
--no-cache |
Skip cache, re-extract all EXIF data |
--help, -h |
Show help |
Examples
loupe # scan current directory
loupe ~/Photos # scan specific path
loupe --json # JSON output (pipe to jq)
loupe --csv > stats.csv # CSV to file
loupe --output stats.csv # same thing
loupe | grep "56mm" # filter results
loupe --json | jq '.focal_lengths' # parse with jq
# Apple Photos library
loupe ~/Pictures/Photos\ Library.photoslibraryInteractive TUI
When run in a terminal without --json or --csv, loupe opens an interactive viewer with bar charts.
| Key | Action |
|---|---|
tab / l / h |
Switch between tabs (Overview, Focal Lengths, etc.) |
1-5 |
Jump to tab by number |
j / k |
Scroll up/down |
s |
Cycle sort: Most used → Value ↑ → Value ↓ → Least used |
q |
Quit |
The Overview tab shows the top 5 and bottom 5 entries for each category.
Apple Photos library
Point loupe at your Photos Library.photoslibrary to analyze your entire Apple Photos library — including photos stored in iCloud that aren't downloaded locally. Loupe reads metadata directly from the Photos SQLite database (strictly read-only, nothing is modified).
loupe ~/Pictures/Photos\ Library.photoslibrarymacOS restricts access to the Photos library. Your terminal app needs Full Disk Access or you'll get a permission error:
- Open System Settings > Privacy & Security > Full Disk Access
- Toggle on your terminal app (Terminal, iTerm2, WezTerm, etc.)
- Restart the terminal
The first run copies the database to a temp directory and queries it, which takes a few seconds. Results are cached for 24 hours. Use --no-cache to force a fresh read.
Supported file types
When scanning a directory, loupe picks up JPEG, HEIC, and common RAW formats:
.jpg .jpeg .heic .heif .cr2 .cr3 .nef .arw .raf .dng .orf .rw2
(Photos library mode reads metadata from the database, so file type doesn't matter — all photo assets are included.)
Piped output
When piped (non-TTY), loupe outputs tab-separated text:
TOTAL IMAGES: 1247
SCANNED: 2026-02-13 10:30 AM
FOCAL LENGTH COUNT PERCENT
56mm 891 71.4%
14mm 203 16.3%
70mm 153 12.3%
Caching
EXIF data is cached in ~/.cache/loupe/. For directory scans, only new or modified files are re-extracted on subsequent runs. For Photos libraries, cached results are reused for 24 hours. Use --no-cache to force a full re-extraction.
- Filter by date range (
--from,--to) - Filter by lens (
--lens "56mm") - Export to HTML report
- Apple Photos library support — analyze your entire library including iCloud-only photos
- Extended file type support: HEIC, CR2, CR3, NEF, ARW, RAF, DNG, ORF, RW2
- Cache moved to
~/.cache/loupe/(no longer writes into scanned directories) - Scan timestamp shown in TUI header and all output formats
- Scan directories recursively for JPEGs
- Extract focal length, aperture, lens, camera from EXIF
- Interactive TUI with bar charts and sort cycling
- Per-file mtime-based EXIF cache for fast repeat runs
- Output as tab-separated, JSON, or CSV
