Skip to main content
Episode progress functions track which episodes of TV shows a user has watched, supporting both individual episode tracking and batch operations for seasons.

markEpisodeWatched

Marks a single episode as watched or unwatched.
tmdbId
number
required
TMDB ID of the TV show
season
number
required
Season number
episode
number
required
Episode number within the season
isWatched
boolean
required
Whether the episode is watched (true) or unwatched (false)
import { api } from "@/convex/_generated/api";
import { useMutation } from "convex/react";

const markEpisode = useMutation(api.watchlist.markEpisodeWatched);

// Mark episode as watched
await markEpisode({
  tmdbId: 1396, // Breaking Bad
  season: 1,
  episode: 1,
  isWatched: true
});

// Unmark episode
await markEpisode({
  tmdbId: 1396,
  season: 1,
  episode: 1,
  isWatched: false
});

Behavior

  • Creates a new episode progress record if it doesn’t exist (when marking as watched)
  • Updates existing record if the watched state changes
  • Does not create a record when unmarking if no record exists
  • Requires user authentication

markSeasonEpisodesWatched

Batch marks multiple episodes in a season as watched or unwatched.
tmdbId
number
required
TMDB ID of the TV show
season
number
required
Season number
episodes
number[]
required
Array of episode numbers to mark
isWatched
boolean
required
Whether episodes are watched (true) or unwatched (false)
import { api } from "@/convex/_generated/api";
import { useMutation } from "convex/react";

const markSeasonEpisodes = useMutation(api.watchlist.markSeasonEpisodesWatched);

// Mark entire season as watched
await markSeasonEpisodes({
  tmdbId: 1396,
  season: 1,
  episodes: [1, 2, 3, 4, 5, 6, 7],
  isWatched: true
});

// Unmark specific episodes
await markSeasonEpisodes({
  tmdbId: 1396,
  season: 1,
  episodes: [1, 2, 3],
  isWatched: false
});

Behavior

  • Processes each episode in the array
  • Only updates records where the watched state actually changes
  • Does not create records when unmarking if they don’t exist
  • Optimized for batch operations (e.g., marking entire seasons)

markShowEpisodesAndStatus

Batch marks episodes across multiple seasons and updates the show’s progress status in a single transaction. This is the most efficient way to mark multiple seasons.
tmdbId
number
required
TMDB ID of the TV show
mediaType
string
required
Type of media (should be “tv”)
seasons
array
required
Array of season objects with episodes to mark
season
number
required
Season number
episodes
number[]
required
Array of episode numbers in this season
isWatched
boolean
required
Whether episodes are watched (true) or unwatched (false)
progressStatus
string
Progress status to set on the show: “want-to-watch”, “watching”, or “finished”
progress
number
Overall show progress percentage (0-100)
title
string
Show title
image
string
URL to show poster image
rating
number
Show rating
release_date
string
Show release date
overview
string
Show description/overview
import { api } from "@/convex/_generated/api";
import { useMutation } from "convex/react";

const markShowEpisodes = useMutation(api.watchlist.markShowEpisodesAndStatus);

// Mark multiple seasons as watched and set status to finished
await markShowEpisodes({
  tmdbId: 1396,
  mediaType: "tv",
  seasons: [
    { season: 1, episodes: [1, 2, 3, 4, 5, 6, 7] },
    { season: 2, episodes: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] },
    { season: 3, episodes: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] }
  ],
  isWatched: true,
  progressStatus: "finished",
  progress: 100
});

Behavior

  • Updates the show’s watch_items record with progress status and percentage
  • Bulk-fetches all existing episode progress records in one query for efficiency
  • Only writes database changes for episodes whose watched state actually changed
  • Replaces the N+1 pattern of calling setProgressStatus + markSeasonEpisodesWatched per season
  • Creates new watch item if the show isn’t tracked yet

getAllWatchedEpisodes

Retrieves all watched episodes for a specific TV show.
tmdbId
number
required
TMDB ID of the TV show
episodes
array
Array of episode progress records
_id
Id<'episode_progress'>
Unique identifier for the episode progress record
userId
Id<'users'>
ID of the user who watched the episode
tmdbId
number
TMDB ID of the TV show
season
number
Season number
episode
number
Episode number
isWatched
boolean
Whether the episode is watched
updatedAt
number
Timestamp of last update
import { api } from "@/convex/_generated/api";
import { useQuery } from "convex/react";

const watchedEpisodes = useQuery(api.watchlist.getAllWatchedEpisodes, {
  tmdbId: 1396
});

// Check if a specific episode is watched
const isEpisodeWatched = watchedEpisodes?.some(
  ep => ep.season === 1 && ep.episode === 1 && ep.isWatched
);

// Count watched episodes
const watchedCount = watchedEpisodes?.filter(ep => ep.isWatched).length ?? 0;

Behavior

  • Returns empty array if user is not authenticated
  • Returns all episode progress records for the show (both watched and unwatched)
  • Useful for displaying watch progress and determining which episodes have been seen

getAllEpisodeProgress

Retrieves all episode progress records for the current user across all TV shows.
episodes
array
Array of all episode progress records for the user
_id
Id<'episode_progress'>
Unique identifier for the episode progress record
userId
Id<'users'>
ID of the user
tmdbId
number
TMDB ID of the TV show
season
number
Season number
episode
number
Episode number
isWatched
boolean
Whether the episode is watched
updatedAt
number
Timestamp of last update
import { api } from "@/convex/_generated/api";
import { useQuery } from "convex/react";

const allProgress = useQuery(api.watchlist.getAllEpisodeProgress);

// Count total watched episodes across all shows
const totalWatched = allProgress?.filter(ep => ep.isWatched).length ?? 0;

// Group by show
const byShow = allProgress?.reduce((acc, ep) => {
  if (!acc[ep.tmdbId]) acc[ep.tmdbId] = [];
  acc[ep.tmdbId].push(ep);
  return acc;
}, {} as Record<number, typeof allProgress>);

Behavior

  • Returns empty array if user is not authenticated
  • Returns all episode progress across all TV shows
  • Useful for syncing progress data or displaying global statistics

syncEpisodeProgressItem

Syncs a single episode’s watch state. Similar to markEpisodeWatched but designed for sync operations.
tmdbId
number
required
TMDB ID of the TV show
season
number
required
Season number
episode
number
required
Episode number within the season
isWatched
boolean
required
Whether the episode is watched (true) or unwatched (false)
import { api } from "@/convex/_generated/api";
import { useMutation } from "convex/react";

const syncEpisode = useMutation(api.watchlist.syncEpisodeProgressItem);

// Sync episode state
await syncEpisode({
  tmdbId: 1396,
  season: 1,
  episode: 1,
  isWatched: true
});

Behavior

  • Identical to markEpisodeWatched in functionality
  • Creates or updates episode progress record
  • Only updates if watched state changes
  • Does not create record when unmarking if none exists

Build docs developers (and LLMs) love