# Letterboxd Films, Ratings & Lists Scraper (`scrapers_lat/letterboxd-scraper`) Actor

Scrape Letterboxd films, member profiles, watchlists and lists: average ratings, cast, genres, runtime, directors. Export JSON, CSV or Excel.

- **URL**: https://apify.com/scrapers\_lat/letterboxd-scraper.md
- **Developed by:** [Scrapers Lat](https://apify.com/scrapers_lat) (community)
- **Categories:** Social media, E-commerce
- **Stats:** 6 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.80 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

[![Letterboxd Films, Ratings & Lists Scraper](https://scrapers.lat/banners/letterboxd-scraper.png)](https://console.apify.com/actors/gmUN88tlQQbDHZegh/input)

## Letterboxd Films, Ratings & Lists Scraper

Here is one real result, with every field the actor returns (cast trimmed to the first 8 of 20 real names, all other values shown in full):

```json
{
  "imageUrl": "https://a.ltrbxd.com/resized/sm/upload/e9/3l/l6/pt/dune-0-600-0-900-crop.jpg?v=a79bf8b4f6",
  "title": "Dune",
  "url": "https://letterboxd.com/film/dune/",
  "slug": "dune",
  "year": 1984,
  "directors": ["David Lynch"],
  "averageRating": 2.85,
  "ratingCount": 295727,
  "reviewCount": 86755,
  "watchCount": null,
  "likeCount": null,
  "listCount": null,
  "runtimeMinutes": 136,
  "genres": ["Adventure", "Science Fiction", "Action"],
  "cast": ["Kyle MacLachlan", "Francesca Annis", "Patrick Stewart", "Linda Hunt", "Jose Ferrer", "Freddie Jones", "Brad Dourif", "Richard Jordan"],
  "synopsis": "In the year 10,191, the most precious substance in the universe is the spice Melange. The spice extends life. The spice expands consciousness. The spice is vital to space travel. The spice exists on only one planet in the entire universe, the vast desert planet Arrakis, also known as Dune. Its native inhabitants, the Fremen, have long held a prophecy that a man would come, a messiah who would lead them to true freedom.",
  "tagline": "A world beyond your experience, beyond your imagination.",
  "languages": ["en"],
  "countries": ["USA"],
  "studios": ["The De Laurentiis Company"],
  "imdbId": "tt0087182",
  "tmdbId": "841",
  "imdbUrl": "https://www.imdb.com/title/tt0087182/",
  "tmdbUrl": "https://www.themoviedb.org/movie/841",
  "memberRating": null,
  "liked": null,
  "listRank": null,
  "memberUsername": null,
  "searchTerm": "dune",
  "sourceType": "search",
  "source": "Letterboxd",
  "observedAt": "2026-08-15T08:18:56.086Z",
  "error": null
}
```

The most complete Letterboxd scraper available. It returns every field a Letterboxd film page exposes (average rating out of 5, rating and review counts, runtime, genres, full cast, directors, synopsis, studios, countries, languages), plus cross-reference fields (IMDb and TMDB IDs and URLs) and member-context fields, and it accepts five source types (film pages, member profiles, watchlists, lists, and browse pages) so you can target exactly the films you need.

**📥 [Input](https://apify.com/scrapers_lat/letterboxd-scraper/input-schema) · 📤 [Output](https://apify.com/scrapers_lat/letterboxd-scraper/output-schema) · 💰 [Pricing](https://apify.com/scrapers_lat/letterboxd-scraper/pricing) · ▶️ [Examples](https://apify.com/scrapers_lat/letterboxd-scraper/examples)**

![Apify](https://img.shields.io/badge/Platform-Apify-1CE1CE?logo=apify\&logoColor=white)
![Coverage](https://img.shields.io/badge/Coverage-Global%20film%20catalog-blue)
![Output](https://img.shields.io/badge/Output-JSON%20%7C%20CSV%20%7C%20Excel-orange)
![Billing](https://img.shields.io/badge/Billing-Pay%20per%20result-brightgreen)

### Table of contents

- [What it does](#what-it-does)
- [Quickstart](#quickstart)
- [Input reference](#input-reference)
- [Output reference](#output-reference)
- [Example output record](#example-output-record)
- [Run via API and CLI](#run-via-api-and-cli)
- [Fetch results](#fetch-results)
- [Billing and limits](#billing-and-limits)
- [FAQ and troubleshooting](#faq-and-troubleshooting)

### What it does

The actor takes a film keyword and/or one or more Letterboxd URLs, resolves each to the films behind it, fetches every film page, and writes one normalized record per film to the run's dataset. It handles five source types: individual film pages, member profile film lists, watchlists, ranked lists, and film browse pages. Numeric ratings are normalized to a 0 to 5 scale, missing source values are returned as `null`, and each film is enriched with IMDb and TMDB identifiers so you can join Letterboxd data to other movie datasets.

Data covers the public Letterboxd film catalog and public member activity. It does not read private profiles, private lists, or anything behind a Letterboxd login.

### Quickstart

Open the actor, paste this into the input, and press Run. It looks up one film by keyword and returns the full film record.

```json
{
  "searchTerm": "dune",
  "maxFilms": 3,
  "withDetails": true
}
```

You can also pass `startUrls` with film pages, member profiles, watchlists, lists, or browse pages instead of (or in addition to) a keyword. Every input field is optional except that you must provide at least a `searchTerm` or one `startUrls` entry.

### Input reference

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `searchTerm` | string | no | (empty) | A film title keyword to look up, for example `dune`. Resolves to the canonical Letterboxd film and is always fully detailed. For an exact film, use `startUrls` with the film URL instead. |
| `startUrls` | array | no | (empty) | Letterboxd URLs to scrape. Accepts film pages (`letterboxd.com/film/dune-2021/`), member profiles (`letterboxd.com/dave/films/`), watchlists (`letterboxd.com/dave/watchlist/`), lists (`letterboxd.com/dave/list/imdb-top-250/`), and film browse pages (`letterboxd.com/films/popular/`). |
| `maxFilms` | integer | no | `10` | Maximum number of films to collect across all inputs. Free Apify plans are capped at 10 per run. |
| `withDetails` | boolean | no | `true` | When on, each film pulled from a member profile, watchlist, list, or browse page is enriched with its full film page (director, average rating, genres, cast, synopsis, runtime, studios). Direct film URLs and keyword searches are always fully detailed. |

You must provide at least a `searchTerm` or one `startUrls` entry. If you pass neither, the actor writes a single item with a populated `error` field and does not charge.

### Output reference

One dataset item per film. Types: `string`, `integer`, `number`, `boolean`, `string[]`, or `null` when the source value is absent.

| Field | Type | Description |
|---|---|---|
| `imageUrl` | string | URL of the film poster image. |
| `title` | string | Film title. |
| `url` | string | Canonical Letterboxd film page URL. |
| `slug` | string | Letterboxd film slug (unique per film), for example `dune`. |
| `year` | integer | Release year, or `null` if unknown. |
| `directors` | string\[] | Director names. |
| `averageRating` | number | Average member rating on a 0 to 5 scale. |
| `ratingCount` | integer | Number of member ratings. |
| `reviewCount` | integer | Number of written reviews. |
| `watchCount` | integer | Number of members who logged the film, or `null` when Letterboxd does not expose it. |
| `likeCount` | integer | Number of members who liked the film, or `null` when not exposed. |
| `listCount` | integer | Number of lists the film appears in, or `null` when not exposed. |
| `runtimeMinutes` | integer | Runtime in minutes. |
| `genres` | string\[] | Genre labels. |
| `cast` | string\[] | Cast member names, in billing order. |
| `synopsis` | string | Plot synopsis text. |
| `tagline` | string | Marketing tagline, or `null`. |
| `languages` | string\[] | Language codes. |
| `countries` | string\[] | Production countries. |
| `studios` | string\[] | Production studios or companies. |
| `imdbId` | string | IMDb title identifier, for example `tt0087182`, or `null`. |
| `tmdbId` | string | TMDB movie identifier, or `null`. |
| `imdbUrl` | string | Full IMDb title URL, or `null`. |
| `tmdbUrl` | string | Full TMDB movie URL, or `null`. |
| `memberRating` | number | The member's own rating on a 0 to 5 scale when the film came from a profile or list, else `null`. |
| `liked` | boolean | Whether the member liked the film when known, else `null`. |
| `listRank` | integer | Position of the film in a ranked list, else `null`. |
| `memberUsername` | string | Username of the member profile, watchlist, or list the film came from, else `null`. |
| `searchTerm` | string | The keyword that resolved to this film, else `null`. |
| `sourceType` | string | Where the film came from: `search`, `film`, `member`, `watchlist`, `list`, or `browse`. |
| `source` | string | Always `Letterboxd`. |
| `observedAt` | string | ISO 8601 timestamp of when the record was collected. |
| `error` | string | `null` on success. On a failed run, a single item with a populated `error` field is written instead. |

### Example output record

Real record from a live run (input `{"startUrls":[{"url":"https://letterboxd.com/film/dune-part-two/"}]}`, cast trimmed to the first 6 real names):

```json
{
  "imageUrl": "https://a.ltrbxd.com/resized/film-poster/6/1/7/4/4/3/617443-dune-part-two-0-600-0-900-crop.jpg?v=cc533700f8",
  "title": "Dune: Part Two",
  "url": "https://letterboxd.com/film/dune-part-two/",
  "slug": "dune-part-two",
  "year": 2024,
  "directors": ["Denis Villeneuve"],
  "averageRating": 4.38,
  "ratingCount": 3561676,
  "reviewCount": 942423,
  "watchCount": null,
  "likeCount": null,
  "listCount": null,
  "runtimeMinutes": 167,
  "genres": ["Adventure", "Science Fiction"],
  "cast": ["Timothee Chalamet", "Zendaya", "Rebecca Ferguson", "Javier Bardem", "Josh Brolin", "Austin Butler"],
  "synopsis": "Follow the mythic journey of Paul Atreides as he unites with Chani and the Fremen while on a path of revenge against the conspirators who destroyed his family. Facing a choice between the love of his life and the fate of the known universe, Paul endeavors to prevent a terrible future only he can foresee.",
  "tagline": "Long live the fighters.",
  "languages": ["en"],
  "countries": ["USA"],
  "studios": ["Legendary Pictures"],
  "imdbId": "tt15239678",
  "tmdbId": "693134",
  "imdbUrl": "https://www.imdb.com/title/tt15239678/",
  "tmdbUrl": "https://www.themoviedb.org/movie/693134",
  "memberRating": null,
  "liked": null,
  "listRank": null,
  "memberUsername": null,
  "searchTerm": null,
  "sourceType": "film",
  "source": "Letterboxd",
  "observedAt": "2026-08-15T08:19:13.423Z",
  "error": null
}
```

### Run via API and CLI

Start a run and wait for it to finish, then read the dataset. Replace `<TOKEN>` with your Apify API token.

Run synchronously and get dataset items in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/scrapers_lat~letterboxd-scraper/run-sync-get-dataset-items?token=%3CTOKEN%3E" \
  -H "Content-Type: application/json" \
  -d '{"searchTerm":"dune","maxFilms":3,"withDetails":true}'
```

Start a run asynchronously:

```bash
curl -X POST "https://api.apify.com/v2/acts/scrapers_lat~letterboxd-scraper/runs?token=%3CTOKEN%3E" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://letterboxd.com/dave/watchlist/"}],"maxFilms":100}'
```

Apify CLI:

```bash
apify call scrapers_lat/letterboxd-scraper \
  --input '{"startUrls":[{"url":"https://letterboxd.com/films/popular/"}],"maxFilms":50}'
```

### Fetch results

Every run writes to a dataset. Fetch items as JSON, CSV, or Excel by changing `format`:

```bash
## JSON
curl "https://api.apify.com/v2/datasets/%3CDATASET_ID%3E/items?token=%3CTOKEN%3E&clean=true&format=json"

## CSV
curl "https://api.apify.com/v2/datasets/%3CDATASET_ID%3E/items?token=%3CTOKEN%3E&clean=true&format=csv"

## Paginate large datasets
curl "https://api.apify.com/v2/datasets/%3CDATASET_ID%3E/items?token=%3CTOKEN%3E&offset=1000&limit=1000"
```

`<DATASET_ID>` is returned as `defaultDatasetId` in the run object. Use `offset` and `limit` to page through large result sets. `clean=true` drops empty and internal fields.

### Billing and limits

- **Pay per result.** You are charged per film record returned (`result` event). See the [pricing tab](https://apify.com/scrapers_lat/letterboxd-scraper/pricing) for the current per-result price.
- **No charge on failure.** If a run errors or no input is provided, the actor writes a single item with a populated `error` field and does not charge for it. Empty runs cost nothing.
- **Spend cap respected.** Set `maxTotalChargeUsd` on the run; once reached, the actor stops emitting and charging further billable results.
- **Free Apify plans** are capped at 10 films per run. Upgrade for higher `maxFilms`.

### FAQ and troubleshooting

**A run returned only an error item. Why?**
You passed neither a `searchTerm` nor any `startUrls`. Provide a film keyword or at least one Letterboxd URL. Error-only runs are not charged.

**Why are `watchCount`, `likeCount`, or `listCount` null?**
Letterboxd does not always expose those counters on the film page. Missing source values are returned as `null`, never invented.

**How do I scrape a member's whole diary or watchlist?**
Pass the member films URL (`letterboxd.com/<user>/films/`) or watchlist URL (`letterboxd.com/<user>/watchlist/`) in `startUrls`. Films from those sources carry `memberRating`, `liked`, and `memberUsername`.

**What rating scale does the actor use?**
All ratings are normalized to a 0 to 5 scale, matching how members rate on Letterboxd.

**Can I join this data to IMDb or TMDB?**
Yes. Each film includes `imdbId`, `tmdbId`, `imdbUrl`, and `tmdbUrl` when Letterboxd links them, so you can match records across datasets.

**Is this an official Letterboxd tool?**
No. This actor is independent and has no affiliation with Letterboxd. It reads only data that is publicly available on the Letterboxd website.

### Related scrapers

- [IMDb Titles Scraper](https://apify.com/scrapers_lat/imdb-titles-scraper): Films and shows with ratings, cast, and crew from IMDb.
- [IMDb Reviews Scraper](https://apify.com/scrapers_lat/imdb-reviews-scraper): User reviews and ratings for any IMDb title.
- [Goodreads Scraper](https://apify.com/scrapers_lat/goodreads-scraper): Books, ratings, and reviews from Goodreads.

### More scrapers at scrapers.lat

Built and maintained by [scrapers.lat](https://scrapers.lat), where we publish scrapers for US and Latin American public platforms: company registries, government data, finance, e-commerce and more. Browse the catalog or request a custom scraper at [scrapers.lat](https://scrapers.lat).

***

> Independent tool, not affiliated with Letterboxd. Accesses only publicly available Letterboxd data.

# Actor input Schema

## `maxFilms` (type: `integer`):

Maximum number of films to collect across all inputs. Optional.

## `withDetails` (type: `boolean`):

When on, each film from a member profile, watchlist, list or browse page is enriched with its full film page (director, average rating, genres, cast, synopsis, runtime, studios). Direct film URLs and keyword searches are always fully detailed.

## `searchTerm` (type: `string`):

A film title keyword to look up, for example "dune". Resolves to the canonical Letterboxd film. For an exact film, paste its film URL below instead.

## `startUrls` (type: `array`):

Letterboxd URLs to scrape. Accepts film pages (letterboxd.com/film/dune-2021/), member profiles (letterboxd.com/dave/films/), watchlists (letterboxd.com/dave/watchlist/), lists (letterboxd.com/dave/list/imdb-top-250/), and film browse pages (letterboxd.com/films/popular/).

## Actor input object example

```json
{
  "maxFilms": 10,
  "withDetails": true
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "maxFilms": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapers_lat/letterboxd-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "maxFilms": 10 }

# Run the Actor and wait for it to finish
run = client.actor("scrapers_lat/letterboxd-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "maxFilms": 10
}' |
apify call scrapers_lat/letterboxd-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapers_lat/letterboxd-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/gmUN88tlQQbDHZegh/builds/mBiNgpPAOHD8UnqYi/openapi.json
