Summary
On GET /sync/watched/shows, the last_updated_at field of the watched-show
wrapper holds a different value under extended=full than under
extended=progress — for the same show, in the same account, from requests
made seconds apart.
This appears to be two semantically different timestamps sharing one key, rather
than one timestamp with drift. I could not find this documented, and it isn't
mentioned in #775.
Related but distinct: api-help#17 compared last_updated_at from
/sync/watched against updated_at from /shows/:id and was closed as
Cloudflare caching. This report is a different comparison — same endpoint,
same field, only extended differs — and the evidence below is not
consistent with a caching explanation.
Environment
- Endpoint:
GET /sync/watched/shows
- Compared:
?extended=full&limit=250 vs ?extended=progress&limit=100
- Account size: 175 watched shows
- Both requests issued back-to-back from the same code path, ~1 second apart
- Observed 2026-07-20, reproduced across several runs hours apart
Steps to reproduce
GET /sync/watched/shows?extended=full&limit=250
GET /sync/watched/shows?extended=progress&limit=100
- Join the two result sets on
show.ids.trakt
- Compare
last_updated_at (the wrapper field, not show.updated_at)
Observed
Across 175 shows: 134 agreed, 41 differed, none null under either variant.
| Show |
extended=full |
extended=progress |
| Die Landarztpraxis |
2026-07-20T16:27:00.000Z |
2026-07-20T16:27:51.000Z |
| The Nanny |
2026-07-14T16:16:00.000Z |
2026-07-14T16:16:24.000Z |
| Villa der Versuchung |
2026-07-05T14:42:00.000Z |
2026-07-05T14:42:12.000Z |
| The Traitors |
2026-07-13T10:00:00.000Z |
2026-07-13T22:25:37.000Z |
| Prominent getrennt – Die Villa der Verflossenen |
2026-07-16T10:00:00.000Z |
2026-07-17T22:11:41.000Z |
The pattern
Three things stand out:
full values are always truncated to the minute (:00.000Z seconds).
progress values carry real seconds. This held across every differing show.
- The
progress value matches /sync/last_activities. In the same refresh
where Die Landarztpraxis reported progress = 2026-07-20T16:27:51.000Z,
/sync/last_activities reported episodes.watched_at = 2026-07-20T16:27:51.000Z — identical to the second.
- The gaps are far larger than clock skew. The Traitors differs by ~12
hours; Prominent getrennt by more than a day.
Working hypothesis: under extended=progress, last_updated_at reflects when
this user's watched progress for the show last changed, while under
extended=full it reflects when the show record itself last changed. The
10:00:00 values under full look like show-level events (episode air times),
and the progress values line up with when the user actually watched.
If that's right, both values are individually reasonable — the problem is that
they share a key, so a client can't tell which one it received.
Why this doesn't look like caching
api-help#17 was closed with "the dates can be different due to Cloudflare
caching." That explanation doesn't fit here:
- Caching would not consistently truncate one variant's seconds to
:00.
- Caching would produce arbitrary skew, not a value that matches
/sync/last_activities to the second.
- Caching would not reproduce the same 41 shows across runs hours apart.
- The two requests were issued ~1 second apart in the same code path.
Why it matters for clients
last_updated_at is the natural change-detection gate for a sync client: store
it per show, re-fetch when it moves. That breaks silently when different code
paths request different extended variants.
Concretely, in our client one pass used extended=full (metadata refresh) and
another used extended=progress (watched-state sync). Both stored the same
field. Each pass saw the other's value as "changed" and overwrote it, so ~41 of
175 shows were reprocessed on every refresh — including a redundant
/shows/:id/next_episode request each. Nothing was visibly broken, which is why
it went unnoticed; we only found it by diffing the two payloads directly.
Workaround: store the two values in separate fields and never compare across
variants.
Questions
- Is this intentional — are these meant to be two different timestamps?
- If so, could the docs state what
last_updated_at means per extended
variant? Distinct keys would be even better.
- Is the minute-truncation under
extended=full intended?
Filed as a follow-up to #875, which covers the field-coverage differences
between these same two variants.
Summary
On
GET /sync/watched/shows, thelast_updated_atfield of the watched-showwrapper holds a different value under
extended=fullthan underextended=progress— for the same show, in the same account, from requestsmade seconds apart.
This appears to be two semantically different timestamps sharing one key, rather
than one timestamp with drift. I could not find this documented, and it isn't
mentioned in #775.
Related but distinct: api-help#17 compared
last_updated_atfrom/sync/watchedagainstupdated_atfrom/shows/:idand was closed asCloudflare caching. This report is a different comparison — same endpoint,
same field, only
extendeddiffers — and the evidence below is notconsistent with a caching explanation.
Environment
GET /sync/watched/shows?extended=full&limit=250vs?extended=progress&limit=100Steps to reproduce
GET /sync/watched/shows?extended=full&limit=250GET /sync/watched/shows?extended=progress&limit=100show.ids.traktlast_updated_at(the wrapper field, notshow.updated_at)Observed
Across 175 shows: 134 agreed, 41 differed, none null under either variant.
extended=fullextended=progress2026-07-20T16:27:00.000Z2026-07-20T16:27:51.000Z2026-07-14T16:16:00.000Z2026-07-14T16:16:24.000Z2026-07-05T14:42:00.000Z2026-07-05T14:42:12.000Z2026-07-13T10:00:00.000Z2026-07-13T22:25:37.000Z2026-07-16T10:00:00.000Z2026-07-17T22:11:41.000ZThe pattern
Three things stand out:
fullvalues are always truncated to the minute (:00.000Zseconds).progressvalues carry real seconds. This held across every differing show.progressvalue matches/sync/last_activities. In the same refreshwhere Die Landarztpraxis reported
progress = 2026-07-20T16:27:51.000Z,/sync/last_activitiesreportedepisodes.watched_at = 2026-07-20T16:27:51.000Z— identical to the second.hours; Prominent getrennt by more than a day.
Working hypothesis: under
extended=progress,last_updated_atreflects whenthis user's watched progress for the show last changed, while under
extended=fullit reflects when the show record itself last changed. The10:00:00values underfulllook like show-level events (episode air times),and the
progressvalues line up with when the user actually watched.If that's right, both values are individually reasonable — the problem is that
they share a key, so a client can't tell which one it received.
Why this doesn't look like caching
api-help#17 was closed with "the dates can be different due to Cloudflare
caching." That explanation doesn't fit here:
:00./sync/last_activitiesto the second.Why it matters for clients
last_updated_atis the natural change-detection gate for a sync client: storeit per show, re-fetch when it moves. That breaks silently when different code
paths request different
extendedvariants.Concretely, in our client one pass used
extended=full(metadata refresh) andanother used
extended=progress(watched-state sync). Both stored the samefield. Each pass saw the other's value as "changed" and overwrote it, so ~41 of
175 shows were reprocessed on every refresh — including a redundant
/shows/:id/next_episoderequest each. Nothing was visibly broken, which is whyit went unnoticed; we only found it by diffing the two payloads directly.
Workaround: store the two values in separate fields and never compare across
variants.
Questions
last_updated_atmeans perextendedvariant? Distinct keys would be even better.
extended=fullintended?Filed as a follow-up to #875, which covers the field-coverage differences
between these same two variants.