A lightweight userscript that extends Letterboxd with external film ratings and useful interface improvements — while keeping the site familiar.
Letterboxd Plus adds Rotten Tomatoes and Metacritic scores directly to film pages, enriches Cast with actor portraits and roles, and provides a native-looking settings panel. It requires no API key and runs entirely in your browser.
Compatible with Tampermonkey,
Violentmonkey,
Greasemonkey,
ScriptCat, and other managers that support the
// ==UserScript== metadata block.
Status: early development. The current release focuses on a reliable foundation, settings, and external film ratings. More Letterboxd enhancements can be added as independent feature modules.
Latest GitHub build:
https://raw.githubusercontent.com/NemoKing1210/letterboxd-plus/main/letterboxd-plus.user.js
| Manager | Installation path |
|---|---|
| Tampermonkey | Dashboard → Utilities → Install from URL |
| Violentmonkey | Dashboard → + → Install from URL |
| Greasemonkey | Add-on menu → New User Script → paste the script |
| ScriptCat | Dashboard → install from URL, then paste the raw GitHub link |
letterboxd-plus.user.js.On Letterboxd film pages, the script adds a compact ratings section to the native sidebar:
The script uses the film title and release year to disambiguate search results. Letterboxd's TMDB identifier is used as the local cache key.
An independent Metacritic section appears alongside the Rotten Tomatoes data:
Matches require the normalized title and a release year within one year of the Letterboxd metadata, which avoids silently selecting unrelated films or remakes.
The final sidebar section combines the Letterboxd rating with every enabled, available external score. Values are normalized to Letterboxd's five-point scale and averaged equally; unavailable scores are omitted.
The Cast section can display compact cards with each actor's portrait, name, and role. Portraits are read from the actor's public Letterboxd page only as cards approach the viewport, with at most three page requests in flight. The first ten actors are shown initially; the rest remain unloaded until Show All is selected and their cards approach the viewport.
Open Letterboxd Plus from:
The accessible tabbed panel follows Letterboxd's visual language and contains:
The dialog supports keyboard tab navigation, arrow keys, Escape to close, visible focus states, mobile layouts, and reduced-motion preferences.
The interface is available in seven languages:
The default Auto mode checks the browser's preferred language list and
selects the first supported language. Regional variants such as es-MX,
pt-PT, and zh-Hans are mapped to the corresponding available translation.
Unsupported or missing browser locales fall back to English. A fixed language
can be selected under Settings → General → Interface language.
0 to 168 hours.0 always requests fresh data.| Site | URL pattern | Behavior |
|---|---|---|
| Letterboxd | https://letterboxd.com/* |
Navigation settings entry and film-page enhancements |
Letterboxd (www) |
https://www.letterboxd.com/* |
Same behavior for the alternate host |
Ratings are mounted only when the page exposes film metadata through
body[data-type="film"][data-tmdb-id].
Letterboxd film page
│
├── read title, year, and TMDB ID from page metadata
│
├── check GM-backed cache
│
├── Rotten Tomatoes search and scorecard
│
└── Metacritic JSON search and movie detail
│
├── strictly match title and release year
├── read critic and audience/user scores
└── cache each provider independently
│
▼
render in Letterboxd sidebar
The page scanner is idempotent and observes dynamic DOM changes, so React navigation updates can restore the account-menu entry without creating duplicates.
Rotten Tomatoes and Metacritic do not provide supported public APIs for this
use case. Letterboxd Plus reads publicly available Rotten Tomatoes pages and
the JSON endpoints used by Metacritic's own website through
GM_xmlhttpRequest.
Enhanced Cast reads public Letterboxd actor pages through same-origin browser requests and displays the portrait URL already supplied there. Results are kept only in memory; no actor biography or portrait data is persisted.
This has several practical consequences:
These cases are handled as reduced functionality rather than Letterboxd page failures. The script does not submit ratings, modify Rotten Tomatoes data, or require account credentials.
The userscript metadata contains @updateURL and @downloadURL values pointing
to the raw GitHub artifact on main. Compatible managers can therefore check
for new releases automatically.
To publish a release:
package.json and package-lock.json.npm run ci to rebuild and verify the root artifacts.letterboxd-plus/
├── src/
│ ├── main.js # Bootstrap and DOM observer
│ ├── constants.js # Settings defaults, keys, URLs, timeouts
│ ├── cache.js # Cache reads, writes, statistics, cleanup
│ ├── settings.js # Settings validation and persistence
│ ├── api/
│ │ ├── letterboxd-person.js # Lazy Letterboxd portrait lookup
│ │ ├── rotten-tomatoes.js # RT search and scorecard parsing
│ │ └── metacritic.js # Metacritic search and score parsing
│ ├── features/
│ │ ├── average-rating.js # Combined normalized rating
│ │ ├── enhanced-cast.js # Cast portrait cards
│ │ ├── film-context.js # Shared Letterboxd film metadata
│ │ ├── film-rating.js # Rotten Tomatoes sidebar integration
│ │ ├── metacritic-rating.js # Metacritic sidebar integration
│ │ ├── rating-section.js # Shared rating section renderer
│ │ └── settings-panel.js # Account-menu entry and settings dialog
│ └── styles/
│ └── main.css # Namespaced Letterboxd-style UI
├── scripts/
│ ├── copy-dist.mjs # Copy dist artifacts to repository root
│ ├── verify-artifacts.mjs # Verify dist and root files match
│ └── lib/artifacts.mjs # Shared artifact names
├── .github/workflows/ci.yml # Build and artifact verification
├── letterboxd-plus.user.js # Installable generated userscript
├── letterboxd-plus.meta.js # Metadata-only generated artifact
├── vite.config.js # Build and userscript metadata
├── package.json # Version, dependencies, npm scripts
├── AGENTS.md # Repository guidance for coding agents
├── CLAUDE.md # Claude entry point for AGENTS.md
└── LICENSE # MIT license
| Path | Purpose |
|---|---|
src/ |
Readable source of truth; make product changes here |
dist/ |
Local Vite output; generated and gitignored |
letterboxd-plus.user.js |
Full install/update artifact |
letterboxd-plus.meta.js |
Lightweight metadata used by update checks |
vite.config.js |
@match, @connect, names, URLs, and build configuration |
| Field | Value |
|---|---|
@namespace |
https://github.com/NemoKing1210/letterboxd-plus |
@match |
Letterboxd apex and www hosts |
@connect |
Rotten Tomatoes hosts and backend.metacritic.com |
@run-at |
document-idle |
@license |
MIT |
@updateURL / @downloadURL |
Raw GitHub userscript on main |
| Grant | Purpose |
|---|---|
GM_xmlhttpRequest |
Request external rating providers across origins |
GM_getValue / GM_setValue |
Persist settings and successful rating cache |
GM_listValues / GM_deleteValue |
Measure and clear cached rating entries |
GM_addStyle |
Inject the bundled interface styles |
GM_registerMenuCommand |
Open settings from the userscript manager |
No access tokens, API keys, passwords, or Letterboxd session data are stored.
Requires Node.js 22 as specified by .nvmrc.
npm install
npm run dev # Serve an installable "dev:" userscript
npm run build # Build dist/ and refresh root artifacts
npm run verify:artifacts # Verify dist and root artifacts are identical
npm run ci # Build and run all repository checks
Edit source files under src/. Userscript metadata is defined in
vite.config.js, and the version comes from
package.json.
After every change:
npm run ci;.user.js and .meta.js artifacts.Do not edit minified generated artifacts directly and do not commit temporary localhost update URLs.
Letterboxd Plus is an independent community project. It is not affiliated with or endorsed by Letterboxd, Rotten Tomatoes, Metacritic, Fandango, or their owners. All product names and trademarks belong to their respective owners.
MIT — Copyright © 2026 NemoKing