Alcides Oliveira

Full-stack software engineer

All projects

Unboxd

Side project · Jan 2026 · Visit site · Private repository

Unboxd is a Stremio add-on. You type a Letterboxd username, and that public watchlist shows up in Stremio as a catalog, with posters and details from TMDB.

I built it alone.

Unboxd, screenshot 1
Setup page: type a Letterboxd username (the watchlist must be public) and install the add-on in Stremio.

Many people keep their list of films to watch on Letterboxd but watch through Stremio. The two apps don’t talk to each other, so every title on the list has to be searched by hand in Stremio. Letterboxd offers no open API for this, so any bridge has to read the watchlist from its public web pages.

The username lives in the install URL

I used Stremio’s configurable manifest instead of storing users. The username travels in every request, so there is no database or login to run. The trade-off is that the server remembers nothing between cold starts, so a new instance scrapes the watchlist again.

Partial results over timeouts

Large watchlists made the first load slow. I moved the IMDb ID lookup into the details request with append_to_response, gave each TMDB call a 5-second timeout, raised parallelism from 20 to 30, and stopped starting new batches after 25 seconds, well inside Vercel’s 60-second limit. Stremio gets the films matched so far instead of a request that times out.

In-memory cache, no external store

I kept the caches inside the function’s memory. On serverless they last while an instance stays warm and disappear after that, but repeat visits in that window skip Letterboxd and TMDB, and the project needs no extra services.

  • A Letterboxd scraper in Node.js with Axios and Cheerio that follows the watchlist pagination and waits one second between pages.
  • The TMDB matching step: a title and year search, then one details request that also returns the IMDb ID through append_to_response. Stremio needs that ID to find streams.
  • The catalog handler with the Stremio Addon SDK: manifest, per-user config, and 100-item pages.
  • A small cache class (a Map with an expiry time per key) used at three levels: watchlist, TMDB results, and finished catalog.
  • A static setup page in HTML and vanilla JavaScript that builds the manifest URL and opens Stremio’s install prompt.
  • The Vercel deploy: a rewrite sends / to the setup page and every other path to a single serverless function running the SDK router, with a 60-second limit.

The setup page asks for a Letterboxd username and an install click. It puts the username, as URL-encoded JSON, inside the manifest URL and opens it with the stremio:// protocol. Stremio then includes that config in every catalog request, so the server keeps no accounts and no database.

When Stremio asks for the catalog, the server walks the user’s watchlist pages on Letterboxd with Axios and Cheerio and reads each film’s name from the poster markup. The year comes from the end of that name when it is there. It then looks up each title on TMDB in batches of 30 parallel requests and turns the results into Stremio entries keyed by IMDb ID, with poster, backdrop, synopsis, and year. Films without an IMDb ID are dropped. Stremio receives the entries 100 at a time through the skip parameter.

Results live in in-memory caches with expiry: 15 minutes for the scraped watchlist, 24 hours for TMDB matches, 10 minutes for the finished catalog. In production the whole add-on runs as one Vercel serverless function; on my machine it runs on Express.

Back end
Node.js, Stremio Addon SDK, Express (local server), Axios, Cheerio, dotenv
Front end
HTML, CSS, vanilla JavaScript
External data
Letterboxd public pages (scraped), TMDB API
Infrastructure
Vercel serverless functions