Recently changed catalog items
Returns Simkl catalog IDs whose metadata changed in the last N days, grouped by type. Use it to keep the items already on a user’s watchlist fresh — when a show airs a new episode, an upcoming title starts airing, or a movie’s metadata is updated, the corresponding ID appears here.
How tracking apps use it
You already know which items the user is tracking from the Sync guide loop (GET /sync/activities + GET /sync/all-items with date_from=). That tells you when the user touched their lists. /changes is the complementary call — it tells you when Simkl’s catalog metadata for any item moved, independent of whether the user touched their list. New episodes that just aired, a show whose status flipped from upcoming to airing, a movie whose runtime / poster / overview was updated.
When to actually call it
Treat it like Sync: trigger on a user-visible event, never on a background timer. The intended cadence is at most once per day per user, gated on a stored timestamp:
| Trigger | What to do |
|---|---|
| App launch / wake-from-background | If now() − last_changes_poll ≥ 24 h, run the loop below and save now() as last_changes_poll. If less than 24 h, skip — the 14-day response window means the same IDs will still be there tomorrow. |
| Manual refresh button | Always allow — bypasses the 24 h gate so the user can force a check. |
| Never | Background setInterval timers, per-user crons, real-time loops, polling on every screen transition. These will get the client_id rate-limited. |
The loop (when the trigger fires)
- Call
/changes?date_from=<last_changes_poll>. Narrow withtype=to only the catalogs the user has items in (skipanimeif the user has no anime, etc.). - Intersect in your client:
{IDs the response returned} ∩ {IDs the user has on any watchlist}. You already have the user’s watchlist locally from the Sync loop — this is a Set lookup, ~microseconds. - Apply the skip rules below to the intersection. Most items get dropped here — only the ones where new metadata is plausible survive.
- For each surviving ID, refetch the matching cached endpoint:
| Refetch for | Endpoint |
|---|---|
| Movie metadata (poster, overview, ratings, release date) | GET /movies/{id} |
| TV show metadata + new episode counts / status | GET /tv/{id} and/or GET /tv/episodes/{id} |
| Anime metadata + new episodes | GET /anime/{id} and/or GET /anime/episodes/{id} |
The detail endpoints are edge-cached by Simkl ID, so popular titles come straight from Cloudflare without hitting origin. When an item’s metadata or episodes change, Simkl automatically purges its Cloudflare cache entry — so a refetch right after /changes flagged the ID is guaranteed to return the fresh data, never a stale edge copy. After the refetch, save now() as last_changes_poll.
Skip rules — when not to refetch
First, restrict the intersect to active lists. Items on the user’s completed and dropped lists are titles they’re done with — there’s no UX win in refreshing metadata for a show they’re never opening again. Intersect /changes only against items on watching, plantowatch, and hold (plus their anime equivalents); drop the rest before you even consider a refetch.
After that filter, the remaining items still benefit from status-based throttling. Cache the last-known status (TV/anime) or release state (movies) for each item in the user’s watchlist, and track the last time you refetched each item. Use the rules below — most items will sit in a state where new metadata is implausible.
| Last-known state | When to actually refetch |
|---|---|
TV / anime, status: airing | Every time the ID appears in /changes — new episodes can drop any week. |
TV / anime, status: tba (upcoming) | Weekly — what matters is the moment the status flips to airing and the first real air date locks in. |
TV / anime, status: ended, ended less than 30 days ago | Every time the ID appears — late corrections to ratings / episode counts happen here. |
TV / anime, status: ended, ended more than 30 days ago | Skip. Refetch once a month at most. Metadata on a finished show is effectively frozen. |
| Movie, released less than 6 months ago | Every time the ID appears — ratings / poster art / overview tend to churn early. |
| Movie, released more than 6 months ago | Skip. Refetch quarterly at most. |
Movie, unreleased / tba | Weekly — you mostly care about the release-date update. |
The intersect + skip combination typically reduces a /changes response of tens of thousands of IDs down to a handful of detail-endpoint refetches per day per user — even for power users with very large libraries.
Query parameters
| Param | Default | Notes |
|---|---|---|
date_from | 14 days ago | ISO date (e.g. YYYY-MM-DD). The server clamps to no older than 14 days ago — older values silently snap to the cap. Invalid values (e.g. BOGUS) silently fall back to the default. Future dates return {}. |
type | anime,shows,movies | CSV. Any combination of anime, shows, movies. Unknown values silently bucket as anime — keep the values in the listed set. Use it to skip catalogs the user doesn’t have anything on. |
Response shape
An object with up to three keys (movies, shows, anime), each an array of integer Simkl IDs. Keys are omitted when their bucket is empty. If nothing changed in the window, the response is {} (an empty object, NOT []).
{
"movies": [
56145,
1029384
],
"shows": [
17465,
92834
],
"anime": [
39687
]
}
IDs are returned in no particular order. Items modified in the last 5 minutes are excluded so partially-written records don’t leak into the delta. Each response contains at most 50,000 IDs — if the catalog produces more (rare; only on very wide windows across all three types), narrow the call with type= to fit under the cap.
Authorizations
Preferred form: your client_id as a URL query parameter on every request. Self-describing in logs and curl commands. See Headers and required parameters.
Headers
Descriptive identifier for your app, ideally name/version. Examples: PlexMediaServer/1.43.1.10540, kodi-simkl/0.9.2, MyApp/2.4.1 (https://myapp.com).
Query Parameters
ISO date (YYYY-MM-DD). Items modified at or after this timestamp are returned. Server caps at 14 days ago — older values silently snap to the cap. Invalid values (e.g. BOGUS) silently fall back to the default. Future dates return {}. Defaults to 14 days ago when omitted.
CSV of types to include. Any combination of anime, shows, movies. Unknown values silently bucket as anime — keep the values in the listed set.
Your client_id from your Simkl developer settings. Required on every request.
Short, lowercase identifier for your app (e.g. plex-scrobbler, kodi-bridge). Helps Simkl identify which apps are using the API.
Your app's current version (e.g. 1.0, 2.4.1). Helps Simkl debug issues you report.
Response
OK
Catalog IDs that changed in the requested window, grouped by type. Each key is OPTIONAL — keys whose bucket is empty are omitted entirely. An all-empty response is {}.