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.
If all you need is “which episodes are airing soon?” — use the Calendar data files on data.simkl.in instead. They’re CDN-cached and give you every upcoming episode in a single fast call:
/calendar/{type}.json) — yesterday + the next ~33 days. The default for “what’s on now and next”./calendar/{year}/{month}/{type}.json) — fetch previous, current, and next month separately when you need a wider calendar grid view (e.g. a 3-month strip).Reserve /changes for the wider job of tracking catalog metadata updates (status flips, ratings, posters, runtimes) on items already on the user’s watchlist.
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.
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. |
/changes?date_from=<last_changes_poll>. Narrow with type= to only the catalogs the user has items in (skip anime if the user has no anime, etc.).{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.| 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.
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.
| 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. |
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.
Documentation Index
Fetch the complete documentation index at: https://api.simkl.org/llms.txt
Use this file to discover all available pages before exploring further.
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.
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).
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.
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 {}.
Was this page helpful?