YouTube Thumbnail Cache: Two Hours, and One ETag for Six Files
Someone changes a thumbnail, and the picture you download is still the old one. Three separate mechanisms explain it, and only the first is about your browser. A real thumbnail arrives with Cache-Control: public, max-age=7200 — it may be kept for two hours without asking again. The tag that is supposed to let a cache ask "has this changed?" is one single value per video, shared by every file size: we sent the maxresdefault tag when requesting five other sizes and all five answered 304 with zero bytes — so the tag cannot report that one size changed. And the fix people reach for, adding ?v=123 to the address, changed nothing the server returned: six different query strings, one identical file. All of it measured on 21 October 2026, every figure read back from the response.
What the server tells a cache: two hours, or thirty seconds
The same host answers a real file and a missing one with very different instructions. Both are cacheable; the durations are two hundred and forty times apart.
| Request | Status | Bytes | Cache-Control | ETag |
|---|---|---|---|---|
/vi/<id>/maxresdefault.jpg (exists) | 200 | 65,324 | public, max-age=7200 | "1749462010" |
/vi/AAAAAAAAAAA/maxresdefault.jpg (missing) | 404 | 1,097 | public, max-age=30 | none |
/vi_webp/AAAAAAAAAAA/maxresdefault.webp (missing) | 404 | 552 | public, max-age=30 | none |
The two hours are why a freshly changed thumbnail can still show as the old picture in a browser you have visited before: nothing is broken, the earlier copy was simply still inside its allowed lifetime. The thirty seconds are the more useful number if you are waiting on a brand-new upload — a miss is only a miss for half a minute, so retrying immediately is the one thing that cannot help, while retrying after a minute can. Our missing-file page covers which sizes disappear in the first place; this page is about the lifetime, not the absence.
Two header facts worth having: there is no Last-Modified on these responses at all, and the ETag is a strong validator (no W/ prefix) containing a plain number. There is also no Vary, no Via and no X-Cache — the only identifying header is Server: sffe.
The same four hosts, the same bytes
Before blaming a cache, it is worth knowing that the host name you use is not a variable. Four names resolve to the same content and hand back identical validators:
| Host | Status | Bytes | SHA-1 (first 12) | ETag | Cache-Control |
|---|---|---|---|---|---|
i.ytimg.com | 200 | 65,324 | 22b4a49df345 | "1749462010" | public, max-age=7200 |
img.youtube.com | 200 | 65,324 | 22b4a49df345 | "1749462010" | public, max-age=7200 |
i3.ytimg.com | 200 | 65,324 | 22b4a49df345 | "1749462010" | public, max-age=7200 |
i9.ytimg.com | 200 | 65,324 | 22b4a49df345 | "1749462010" | public, max-age=7200 |
Three fetches of one address, spaced five and ten seconds apart, returned the same 65,324 bytes and the same fingerprint each time — while the Age header moved 5,438 → 2,019 → 5,118. Age is how long the copy you got has been sitting in a cache somewhere, so that jump is just you landing on different machines. It is not a signal that the picture changed.
The tag is per video, not per file — and this is the trap
Here is the measurement that makes "just check the ETag" fail. One video, six sizes, six genuinely different files. We took the ETag from the largest file and sent it back as If-None-Match when asking for each of the others:
| File requested | Its real size | Its own SHA-1 | Answer with the maxres ETag |
|---|---|---|---|
maxresdefault.jpg | 65,324 B | 22b4a49df345 | 304 · 0 B |
hq720.jpg | 65,324 B | 22b4a49df345 | 304 · 0 B |
sddefault.jpg | 31,029 B | 9273a2b254b5 | 304 · 0 B |
hqdefault.jpg | 21,011 B | 24ca0ed0e641 | 304 · 0 B |
mqdefault.jpg | 10,303 B | 2b0581c9d98c | 304 · 0 B |
default.jpg | 2,888 B | 8835b28d0a39 | 304 · 0 B |
Six different files, from 65,324 bytes down to 2,888, and one tag satisfies all of them. Whatever that number describes, it describes the video's picture set, not any single file inside it. The practical consequence is blunt: if you ask "did this size change?" with an ETag, the answer you get is about the set, and a "not modified" reply tells you nothing about the file you asked for.
And the number is not a content hash. Across six videos the values were "1749462010", "1415628355", "1551160317" and "1572536797", with two videos having no tag at all because their maxresdefault returned 404. Read as Unix seconds, those are 9 June 2025, 10 November 2014, 26 February 2019 and 31 October 2019. The first of those videos was published on 24 October 2009 — five thousand seven hundred days before the number — so the tag is not the upload date. (Inference, labelled as such: the value looks like the moment the picture set was last rebuilt. We could not observe a rebuild happening, so we state what it is not — an upload date, and a content hash — rather than claim what it is.)
And on a new video the tag is literally zero
We checked all nineteen videos on our own channel, every one of them published within the past month. All nineteen carry ETag: "0" — on the 1280 × 720 file and on the 480 × 360 file alike, despite those files ranging from 29,352 to 94,891 bytes. Sending If-None-Match: "0" back got a 304 with zero bytes on all three we tried. So the tag is present, it validates, and it still carries no information about which picture it validated.
(Inference, labelled as such: a newer video still reading "0" suggests the number is written by a later pass over the video rather than at upload. Nineteen videos from one channel is a small sample and we are not claiming every new video behaves this way.)
Adding ?v=123 to the address does nothing the server cares about
This is the most common advice for "force a fresh copy", so we tested it directly — the same file with six different query strings:
| Address requested | Status | Bytes | SHA-1 | ETag returned |
|---|---|---|---|---|
maxresdefault.jpg | 200 | 65,324 | 22b4a49df345 | "1749462010" |
maxresdefault.jpg?v=1 | 200 | 65,324 | 22b4a49df345 | "1749462010" |
maxresdefault.jpg?v=2 | 200 | 65,324 | 22b4a49df345 | "1749462010" |
maxresdefault.jpg?t=1700000000 | 200 | 65,324 | 22b4a49df345 | "1749462010" |
maxresdefault.jpg?sqp=abc | 200 | 65,324 | 22b4a49df345 | "1749462010" |
maxresdefault.jpg?x=1&y=2 | 200 | 65,324 | 22b4a49df345 | "1749462010" |
Identical, six times over, including the querystring that unrelated pages use for signing (the hover-preview page shows what a signature actually gates — a different path, not this one). The trick is not worthless: a different query string is a different address, so your own browser's cached copy is no longer a match and it will re-ask. But the answer it gets is the same file, because the file never changed. If the picture really was replaced and you still see the old one, the stale copy is somewhere between you and the source, and no query string reaches into it.
Two smaller things that will look like a broken image
| What was asked for | Status | Bytes | What came back |
|---|---|---|---|
/vi/<id>/MAXRESDEFAULT.JPG | 404 | 1,097 | the grey placeholder |
/vi/<id>/maxresdefault.jpg/ (trailing slash) | 404 | 1,097 | the grey placeholder |
The path is case-sensitive and does not tolerate a trailing slash. Both mistakes return a valid 120 × 90 image rather than an error, which is why they get blamed on the cache — compare the bytes instead; the verification page has the fingerprint to check against.
How to actually tell whether a thumbnail changed
- Compare the file itself, not the tag. Fetch the bytes and hash them — a real change moves both the byte count and the digest. On these files every size has a different digest, and the tag is identical across sizes, so the digest is the only one of the two that answers the question you asked.
- Give the two hours their two hours. If you have loaded the image before, your copy is legitimate for
max-age=7200. A cache-busting query gets you a fresh fetch; it does not get the world a fresh picture. - After a new upload, wait at least 30 seconds between tries. That is the lifetime of the miss. Rapid retries inside that window are guaranteed to return the same placeholder.
- Do not read
Ageas freshness. It measures how long a cache has held the copy, and we saw it jump around by three thousand seconds between requests seconds apart. - If you are changing your own thumbnail: the upload-side steps and the sizes YouTube asks for are on the change-a-thumbnail page; the byte sizes each name returns are on the file-size page.
Questions people actually ask
"I changed the thumbnail but the download still shows the old one. Which end is wrong?"
Neither, usually. The previous response allowed a copy to be kept for 7,200 seconds, so anything holding that copy is behaving correctly. Measured on 21 October 2026; the same 65,324 bytes came back from all four image hosts with that same lifetime.
"Will adding ?v=123 force the new picture?"
It forces a new request, not a new picture. Six query strings returned the same 65,324 bytes, the same SHA-1 22b4a49df345 and the same ETag. What it does buy you is that your own browser no longer matches its cached entry.
"Can I use the ETag to detect that a thumbnail was updated?"
Not reliably, and for a specific reason: one tag covers all six sizes. We sent the maxresdefault tag against five other sizes and got 304 with zero bytes every time. A "not modified" therefore means "this video's picture set is unchanged as far as this tag knows", not "the file you asked for is unchanged".
"Is the ETag a hash of the image?"
No. Six files whose bytes and SHA-1 digests all differ returned the identical tag. The value is a plain number, it differs per video, and on all nineteen videos of a channel published in the last month it is literally "0".
"Why does a brand-new video give me a grey square?"
Because the big file has not been produced yet, and that miss is only cached for 30 seconds — two hundred and forty times shorter than a real file's two hours. Waiting a minute and asking again is the whole fix. The missing-size page explains which videos never get a large file at all.
Every figure on this page was read from a response we made ourselves on 21 October 2026: four hosts compared on one file, one address fetched three times with gaps, six sizes validated with a single ETag, six query strings compared byte for byte, six public videos and nineteen of our own checked for their tag values, plus HEAD-versus-GET and two malformed paths. No picture is reproduced here and no channel is named. Two things we did not measure and therefore do not claim: how long a replaced thumbnail takes to reach every cache in the world, and what the numeric tag is written from — for the second we say only what it demonstrably is not. Two statements on this page are marked as inference where they appear. Nothing here is an estimate.