active, completed, or closed). Up to 50 sessions per item. Simkl returns the full session list so you can replicate the simkl.com “Rewatches” panel.
Simkl Pro / VIP only. Free-tier callers with
?allow_rewatch=yes get a silent no-op — the request still consumes a rate-limit slot but returns added: { movies: 0, shows: 0, episodes: 0 }. Gate the flag behind the user’s plan instead of sending it blindly:- On sign-in (or first launch), call
POST /users/settingsonce and readaccount.type— one of"free","pro", or"vip". Cache it locally. - Don’t refetch on every poll. User settings are set-and-forget. Watch
activities.settings.allfromGET /sync/activities(you’re already polling it for the sync delta — see the Sync guide); when that timestamp bumps, refetch/users/settingsonce to pick up plan upgrades, downgrades, timezone changes, etc. - If
account.type === "free", hide or disable the “Rewatch” button with a short note like “Rewatch tracking requires Simkl Pro or VIP” and link to simkl.com/vip. Don’t send?allow_rewatch=yesfor free-tier users — there’s no value in firing a request that the server will silently drop.
Endpoints used
POST /sync/history
Write watch events.
?allow_rewatch=yes makes the write land in a rewatch session instead of the canonical row.GET /sync/all-items
Read sessions back.
?allow_rewatch=yes adds one extra row per saved session alongside the canonical entry.Quick start
A movie rewatch:rewatch_id and rewatch_status inside added.statuses[].response. Cache the rewatch_id and pin it on every subsequent write for that session.
When does a write become a rewatch?
The server always tries the regular write first. If the regular write would actually mark new data, that takes precedence — no rewatch is created. A write lands in a rewatch session when any of these holds:- The item is already Completed and the regular add is a no-op (movies: user already finished it; shows: payload has no episodes and the show is Completed).
- You included episodes and every one is already on the user’s history — i.e. the regular write would change nothing.
- You passed
is_rewatch: trueon the item.
is_rewatch: true does not bypass the regular-first logic. If the write tries to add a date that already exists in canonical history, it’s still rejected. The flag’s main use is to create an empty rewatch session on a Completed item your UI explicitly marked as “starting a rewatch” — without writing any episodes yet.
The episode or movie must already exist on the user’s history (completed / watching / hold / dropped) — Plan-to-Watch entries can’t be rewatched, there’s nothing to rewatch.
Per-item rewatch fields
All fields below are optional. They only take effect when?allow_rewatch=yes is on the URL.
Session states
A session is in exactly one of three states. For TV / anime,completed is server-earned only: the server promotes a session when the rewatch covers every aired regular episode (specials in season 0 don’t count). For movies, completed is the default and only meaningful state.
Transitions you can drive from a write (
POST /sync/history?allow_rewatch=yes + rewatch_status: "..."):
"active"— start or reactivate a session. The previously-active session for the item auto-closes."closed"— end the active session. No-op against acompletedsession; reactivate it first if you really need to close it."completed"— honored for movies. For TV / anime, silently clamped to"closed"because only coverage earns DONE. Subsequent episode writes that complete coverage will promote the session back to"completed".
completed session (whether active or closed) auto-promotes to completed the moment an episode write pushes coverage to every aired regular episode.
The 2-day gap
Any two watch events on the same item (movie or individual episode) must be at least 2 days apart, or the second write collapses into the first session. It’s a rewatch, not a rewind 😄. The gap is per-item, not per-show. Watching S1E1 on Monday and S1E2 on Tuesday is fine — those are different items. The rule only fires when the same episode is written twice within 48h.Why a 2-day gap? It absorbs common timestamping problems that would otherwise inflate the user’s history with phantom rewatches:
- Sleep-and-resume — user starts an episode at night, finishes the next morning. One viewing, not two.
- Wrong timezones — clients labeling local time as UTC (or vice versa) drift 1–12 hours per write.
- DST transitions — naive date libraries miscalculate by an hour twice a year.
- Multi-device duplicates — phone + TV both report the same play.
- Retry storms — flaky connections retry a write that already landed.
- Importer re-runs — re-running an import re-sends the same
watched_at. - Scrobble pause/resume noise — bathroom break → re-fire of
/start+/stop. - Buggy progress reporting — players hitting 80%+ multiple times on seeks.
Reading sessions back
?allow_rewatch=yes on GET /sync/all-items adds one extra entry per saved rewatch session alongside the canonical entry for each item. Always pair with date_from — never call without it outside the initial Phase-1 sync.
Canonical vs rewatch rows
The canonical row and the rewatch rows are independent:
last_watched_at and watched_episodes_count on the canonical entry never incorporate rewatch progress, no matter how many sessions exist for the item.
Worked example — Game of Thrones with one rewatch session
A representative shape fromGET /sync/all-items?allow_rewatch=yes&extended=full&episode_watched_at=yes — Game of Thrones (Simkl ID 17465) finished long ago, currently being rewatched in progress (4 of 73 episodes into S1). The item appears twice in shows[]: once as the canonical row, once as the in-progress rewatch row.
- Same
simklID on both rows —17465appears twice. Group byids.simklwhen iterating; treatis_rewatch: truerows as side-cars on the canonical entry. - Canonical
watched_episodes_countis73/73(the user finished the show originally); the rewatch row’s4/73is per-session and does NOT advance the canonical count. last_watched_atis independent on each row — canonical reflects the original final watch (2026-05-15); the rewatch row reflects its own most-recent episode (2026-05-16T20:00:00Z).rewatch_status: "active"because the session is mid-coverage (4/73). It auto-flips to"completed"whenwatched_episodes_count >= total_episodes_count - not_aired_episodes_count. See Session states for the full rules.seasons[].episodes[]only appears on the rewatch row under this flag combo (extended=full+episode_watched_at=yes). Withoutextended=full, the rewatch row would arrive summary-only:watched_episodes_count: 0sentinel, noseasons[]block.- Movies are simpler — no
seasons[], justmovie: { ... }, and the rewatch row’srewatch_statusalways starts atcompleted(movies have nothing to track episode-wise). - Anime rewatch rows have the same shape as show rows plus an
anime_typefield ("tv","movie", etc.) on the rewatch row itself.
Flag combinations for episode lists
episode_watched_at=yes is a modifier — it adds timestamps to episodes already loaded. Without extended=full, episodes aren’t loaded and the flag has no effect on rewatch entries.
UI patterns (mirror simkl.com)
Stats badge — '×3 times (1 partial), last 12 days ago'
Stats badge — '×3 times (1 partial), last 12 days ago'
Filter
?allow_rewatch=yes response for the current item and count by rewatch_status. closed is the “partial” count; completed is the clean-finish count.'Currently rewatching #N' progress bar (TV / anime)
'Currently rewatching #N' progress bar (TV / anime)
Find the
active session and show watched_episodes_count / total_episodes_count. Number the badge by chronological index among all sessions for the item — the number isn’t stored on the server, you compute it client-side.Movies don’t really have an active phase — every movie rewatch session flips to completed immediately.Rewatch history list — '×3 sessions' panel
Rewatch history list — '×3 sessions' panel
Filter rewatch entries, sort by
last_watched_at ascending. Label sessions “Rewatch #1”, “Rewatch #2”, etc. on the client.Limits and rules
- Maximum 50 rewatches per item (movie, show, or anime — combined cap).
- One
activesession per item. Making another session active auto-closes the previous active one. - 2-day minimum gap between watch events on the same movie or episode. See The 2-day gap.
- Simkl Pro / VIP only. Free-tier writes are silent no-ops.
Edge cases
Free-tier user calls `?allow_rewatch=yes`
Free-tier user calls `?allow_rewatch=yes`
Returns
200 OK with added: { movies: 0, shows: 0, episodes: 0 }. No error code is surfaced. To prevent this in your app, check account.type from POST /users/settings at sign-in (cache it locally; refetch only when activities.settings.all bumps — see the Pro / VIP gate at the top of this page). Reading the added counts in the response is a fallback if you can’t gate up-front, but it’s wasteful — the request still consumed a rate-limit slot.50-cap reached
50-cap reached
Subsequent attempts past 50 may start being rejected once server-side enforcement is added. Count sessions client-side before exposing a “Start new rewatch” button.
Active session collision
Active session collision
Starting a new active session auto-closes the previous one (its
watched_episodes_count is preserved). The old session is still readable and still counts toward the 50-cap.`watched_at` collides with canonical history
`watched_at` collides with canonical history
A rewatch write — including one with
is_rewatch: true — is rejected if the watched_at date matches an existing canonical episode/movie row. Use a different watched_at value, or omit the conflicting episode.Same episode written twice within 48h
Same episode written twice within 48h
Second write collapses into the same session.
watched_episodes_count doesn’t increment; last_watched_at updates to the latest value. Intentional — see The 2-day gap.Conflict-split on same episode, different dates
Conflict-split on same episode, different dates
If an episode is already in the active session but a new write for that same episode arrives with a
watched_at more than 48h away, the server closes the current active session (preserving its watched_episodes_count) and opens a fresh active session with the conflicting episode at the new timestamp. Common with offline-capable apps catching up after a long sync gap.Sessions started via simkl.com are pre-populated
Sessions started via simkl.com are pre-populated
When a rewatch session is created through the simkl.com web UI’s “Start new rewatch” button, the server bulk-inserts episode rows for every episode the user had previously watched (a snapshot of their prior progress). Sessions created via plain API writes don’t do this. Re-fetch
/sync/all-items after a session was created on simkl.com to see what’s actually there.`1970-01-01T00:00:01Z` on a rewatch episode
`1970-01-01T00:00:01Z` on a rewatch episode
Intentional “watched, date unknown / long ago” placeholder — not a NULL or bug. See Dates and timezones → “Very long time ago” placeholder.
Reference
Sync guide
Two-phase model,
date_from semantics, deletion reconciliation, edge cases.Mark as watched
Simple “mark watched” flow without rewatch sessions.
POST /sync/history
Endpoint reference + interactive playground.
GET /sync/all-items
Endpoint reference + interactive playground.