Am I the only one with friends forcing me to join Letterboxd?

I come from TV Time. The app is notorious for blocking users from accessing their data. So I had to find another way, since I have hundreds of movies to transfer.

A monopage app coded with Flutter

Luckily for us, it’s possible to access TV Time on the web.

  1. Login
  2. Go to your profile
  3. Go to your movie list.

I quickly realized that the HTML DOM isn’t available. It’s because of Flutter’s shadow DOM (if I got it right).

We need to think outside the box.

The Network tab

In the developer console (Ctrl/Cmd + Shift + C), go to the Network tab.

By doing a hard refresh a pretty big json is fetched.

The json is fetched from https://app.tvtime.com/sidecar?o=https%3A%2F%2Fmsapi.tvtime.com%2Fprod%2Fv1%2Ftracking%2Fcgw%2Ffollows%2Fuser%2F<user_id>&entity_type=movie&sort=watched_date%2Cdesc. It weights ~400kb for ~200 movies.

Click on it, and on Response the json looks like this :

{
    "status": "success",
    "data": {
        "user_id": 12345678,
        "type": "list",
        "objects": [
            {
                "uuid": "1f663b20-66d9-5f07-b6eb-59225ffea406",
                "type": "follow",
                "...": "..."
            }
        ]
    }
}

Get the json on Firefox

Get the json on Chrome/Chromium

If it’s correct, copy/paste its contents to a file named tvtime.json.

Transform the json with jq

Letterboxd has a csv importer tool. That’s why we need to convert the json so it can be read by Letterboxd.

We need a list with titles, release years and watched dates.

Install jq first.

On the WatchedDate column, I grab the watched date. As some of them don’t have this field, I had to fill them out with a default date.

So you need to change the part with 2025-05-19 to your preference, inside the script.

jq -r '
  (["Title","Year","WatchedDate"]),
  ( .data.objects[] |
    [
      .meta.name,
      (.meta.first_release_date | split("-")[0]),
      (.watched_at // "" | if length > 0 then split("T")[0] else "2025-05-19" end)
    ]
  )
  | @csv
' tvtime.json > letterboxd.csv

The following is for PowerShell users (doesn’t use jq)

$json = Get-Content -Raw -Path "tvtime.json" | ConvertFrom-Json
$csvLines = @()
$csvLines += '"Title","Year","WatchedDate"'

foreach ($item in $json.data.objects) {
    $title = $item.meta.name
    $year = ($item.meta.first_release_date -split "-")[0]

    if ($item.watched_at) {
        $watchedDate = ($item.watched_at -split "T")[0]
    } else {
        $watchedDate = "2025-05-19"
    }

    $csvLine = '"' + $title.Replace('"', '""') + '","' + $year + '","' + $watchedDate + '"'
    $csvLines += $csvLine
}

$csvLines | Set-Content -Path "letterboxd.csv" -Encoding UTF8

Import the csv on Letterboxd

On the import page, open the letterboxd.csv file.

We need to manually import the movies that weren’t recognized. Check Hide successful matches to fill them up.

Then click on Import films.


If you have any questions or suggestions, feel free to contact me by email, on LinkedIn, or directly by sending an issue on GitHub.