Transform your Letterboxd film diary into a beautiful GitHub-style contribution graph
| Feature | Description |
|---|---|
| π¨ Light & Dark Themes | Automatically adapts to GitHub's theme preference |
| π Activity Heatmap | GitHub-style contribution graph showing film activity |
| π€ Profile Integration | Shows profile picture, display name, stats, and member badge |
| π Pro/Patron Badges | Displays Letterboxd Pro (orange) or Patron (cyan) status |
| π Multi-Year Support | Generate graphs spanning multiple years |
| π― Streak Highlighting | Hover over "Day Streak" to highlight your longest streak |
| π¬ Interactive Tooltips | Hover over cells to see film details (in browser) |
| β Rating Mode | Color cells by average rating instead of watch count |
| π¦ JSON Export | Writes images/letterboxd-data.json for external widgets (e.g. Glance custom-api) |
| π Daily Updates | Automated updates via GitHub Actions |
Click the Fork button at the top-right of this page.
Edit .github/workflows/update-graph.yml:
- run: npm start YOUR_LETTERBOXD_USERNAME -o images/github-letterboxdGo to Actions tab β Enable workflows if prompted.
The graph updates daily at midnight UTC, or trigger manually via the Actions tab.
Hover over stats to reveal additional information (visible when opening the SVG in a browser):
| Day Streak Highlight | Days Active Tooltip | Film Count Tooltip |
|---|---|---|
![]() |
![]() |
![]() |
# Install dependencies
npm install
# Basic usage
node src/cli.js <username>
# With options
node src/cli.js <username> [options]| Flag | Description | Default |
|---|---|---|
-y <years> |
Year(s) to generate, comma-separated (e.g. 2024,2023) |
Current year |
-w <day> |
Week start: sunday or monday |
sunday |
-o <path> |
Output path (without extension) | images/github-letterboxd |
-g <bool> |
Enable username gradient: true or false |
true |
-p |
Export PNG files in addition to SVG | Disabled |
-m <mode> |
Graph mode: count or rating |
count |
# Single year with custom output
node src/cli.js nichtlegacy -y 2025 -o images/my-graph
# Multiple years (2024 + 2025)
node src/cli.js nichtlegacy -y 2025,2024
# Start week on Monday, no gradient
node src/cli.js nichtlegacy -w monday -g false
# Rating mode with PNG export
node src/cli.js nichtlegacy -m rating -pCreate .github/workflows/update-graph.yml:
name: Update Letterboxd Graph
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# β CONFIGURATION - Edit these values for your Letterboxd profile β
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
env:
LETTERBOXD_USERNAME: "YOUR_USERNAME" # Replace with your username
YEARS: "" # e.g. "2025,2024" or leave empty for current year
EXPORT_PNG: "false" # Set to "true" to also generate PNG files
WEEK_START: "sunday" # "sunday" or "monday"
GRADIENT: "true" # "true" for colored name, "false" for white
on:
schedule:
- cron: "0 0 * * *" # Daily at midnight UTC
workflow_dispatch: # Manual trigger
permissions:
contents: write
jobs:
update-graph:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Generate Graph
run: |
# Build command based on configuration
CMD="node src/cli.js ${{ env.LETTERBOXD_USERNAME }} -o images/github-letterboxd"
if [ -n "${{ env.YEARS }}" ]; then CMD="$CMD -y ${{ env.YEARS }}"; fi
if [ "${{ env.WEEK_START }}" = "monday" ]; then CMD="$CMD -w monday"; fi
if [ "${{ env.GRADIENT }}" = "false" ]; then CMD="$CMD -g false"; fi
if [ "${{ env.EXPORT_PNG }}" = "true" ]; then CMD="$CMD -p"; fi
echo "Running: $CMD"
eval $CMD
- name: Commit and Push
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add images/
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "Update Letterboxd graph"
git push
fiYou can customize the graph directly in the workflow file by editing the env section at the top:
- LETTERBOXD_USERNAME: Your Letterboxd profile name
- YEARS: Comma-separated list of years (e.g.,
2025,2024) - EXPORT_PNG: Set to
trueif you want PNG versions alongside SVGs - WEEK_START: Start week on
sundayormonday - GRADIENT: Toggle the username text gradient
The generator also writes images/letterboxd-data.json, so you can build Glance widgets without running an extra backend container.
Raw URL format:
https://raw.githubusercontent.com/<github-user>/letterboxd-graph/main/images/letterboxd-data.json
Example payload shape:
{
"user": "nichtlegacy",
"year": 2026,
"stats": { "films": 123, "daysActive": 80, "streak": 7 },
"cells": [
{
"date": "2026-02-16",
"count": 2,
"ratingAvg": 3.5,
"films": [
{ "title": "Film A", "year": "2024", "rating": 3.5, "url": "https://letterboxd.com/..." }
],
"url": "https://letterboxd.com/<user>/films/diary/for/2026/02/16/"
}
],
"recent": [
{ "date": "2026-02-16", "title": "Film A", "year": "2024", "rating": 3.5, "url": "https://letterboxd.com/..." }
]
}You can use this to build:
- a compact heatmap widget (GitHub-like)
- a separate stats widget (
films,daysActive,streak) - an optional recent-watches list
letterboxd-graph/
βββ .github/
β βββ assets/ # README images and examples
β βββ workflows/
β βββ update-graph.yml # GitHub Actions workflow
βββ fonts/
β βββ Inter-Bold.ttf
β βββ Inter-Medium.ttf
β βββ Inter-Regular.ttf
β βββ Inter-SemiBold.ttf # Primary font for text measurement
βββ images/
β βββ github-letterboxd-dark.svg # Generated dark theme
β βββ github-letterboxd-light.svg # Generated light theme
β βββ letterboxd-data.json # Generated JSON data for widgets
βββ src/
β βββ cli.js # CLI entry point
β βββ fetcher.js # Letterboxd data fetching
β βββ generator.js # SVG generation
β βββ stats.js # Statistics calculations
β βββ exporter.js # PNG export functionality
βββ package.json
βββ README.md
Add this to your profile README to display the graph with automatic theme switching:
<p align="center">
<a href="https://letterboxd.com/YOUR_LETTERBOXD_USERNAME/" target="_blank">
<picture>
<source
media="(prefers-color-scheme: dark)"
srcset="https://github.com/YOUR_GITHUB_USERNAME/letterboxd-graph/blob/main/images/github-letterboxd-dark.svg"
/>
<source
media="(prefers-color-scheme: light)"
srcset="https://github.com/YOUR_GITHUB_USERNAME/letterboxd-graph/blob/main/images/github-letterboxd-light.svg"
/>
<img
alt="Letterboxd contribution graph"
src="https://github.com/YOUR_GITHUB_USERNAME/letterboxd-graph/blob/main/images/github-letterboxd-light.svg"
/>
</picture>
</a>
</p>Replace YOUR_GITHUB_USERNAME and YOUR_LETTERBOXD_USERNAME with your usernames.
| Mode | Description |
|---|---|
| Count (default) | Cell color intensity based on number of films watched |
| Rating | Cell color based on average rating of films that day |
The graph automatically detects and displays your Letterboxd membership status:
| Status | Badge Color | Location |
|---|---|---|
| Pro | Orange (#ff8000) | Bottom-left of profile picture |
| Patron | Cyan (#40bcf4) | Bottom-left of profile picture |
- Node.js v18 or higher
- Public Letterboxd profile with diary entries
- GitHub account with Actions enabled (for automated updates)
Contributions are welcome! Feel free to:
- π Report bugs
- π‘ Suggest features
- π§ Submit pull requests
MIT License - see LICENSE for details.


