How to read the thumbnail tester
The thumbnail tester takes an image — a file you choose, or a video's current thumbnail pulled from its URL — and renders it inside generic video-platform mockups at true display sizes, then in a small-size strip, with an optional second image and a grayscale toggle. Each view prints something: a status line with dimensions, a ratio, and a crop percentage; a size on every surface; a label on every slot. This guide explains what each readout means, how it is computed, and where it stops. Every figure below is produced at build time by the module that runs the tool.
The four preview surfaces are typicals, not a spec
The tester renders your image in 4 slots — Home grid card (desktop) at 320×180, Suggested / sidebar row at 168×94, Search result row at 246×138, Mobile list row at 160×90 — each set to a fixed CSS pixel size. Those sizes are honest current typicals of how video platforms size those surfaces — platforms shift them a few pixels with every redesign — so every label says "typical" and none is a specification. What the slot does is exact, though: your browser scales the image into that pixel budget, so what you see is the detail that survives at that size.
Home grid card (desktop) and Mobile list row are exactly 16:9. Suggested / sidebar row and Search result row cannot be: 16:9 at 168 px wide wants 94.5 px of height, and a whole-pixel slot cannot land on a fractional height, so the slot uses 94. The difference is invisible, but it is why aspect-ratio math matters even at preview scale; the tester page tabulates each slot's reduced ratio and the exact 16:9 height its width implies. The 16:9 target is not the tester's invention: Google's help documentation recommends it as the most-used shape in players and previews, cited to Google's "Add video thumbnails" article (verified July 25, 2026) on the size guide.
The text around each slot — title, channel, views-and-time line, duration badge — is editable, because a thumbnail is never displayed alone; a blank duration field hides the badge. The badge sits bottom-right because that is where the convention puts it; safe areas, explained covers that convention and the other typical overlay zones.
Reading the status line
When an image loads, the slot prints one line in a fixed shape: Loaded: label — width×height (ratio); crop sentence. Dimensions are the decoded pixel size of the file — what the bytes contain, not what the file name or an export dialog claims. The ratio is width:height reduced by their greatest common divisor, so 320×180 prints as 16:9 and 1000×562 prints as 500:281. The 16:9 verdict is exact integer arithmetic — width × 9 must equal height × 16 — with no tolerance. The crop sentence comes from the cover-crop report: what a 16:9 slot with a cover fit hides, and on which axis.
| Upload size | Reduced ratio | Verdict | Hidden in a 16:9 slot |
|---|---|---|---|
| 1280×720 — the long-standing working standard | 16:9 | exact 16:9 | nothing |
| 640×480 — the 4:3 storage frame of sddefault | 4:3 | not 16:9 — height is cropped | 25% of the height |
| 1080×1080 — a square export | 1:1 | not 16:9 — height is cropped | 43.8% of the height |
| 1080×1920 — a vertical export | 9:16 | not 16:9 — height is cropped | 68.4% of the height |
| 2560×1080 — an ultra-wide banner | 64:27 | not 16:9 — width is cropped | 25% of the width |
| 1000×562 — a near miss — see below | 500:281 | not 16:9 — width is cropped | 0.1% of the width |
The arithmetic is short. An image wider than 16:9 keeps a width of height × 16 ÷ 9 and loses the rest from the sides; a taller one keeps a height of width × 9 ÷ 16 and loses the rest from top and bottom. The lost share is divided by the original axis and rounded to one decimal, so the 4:3 frame at 640×480 loses 25% of its height, while the 64:27 banner loses 25% of its width.
Three misreadings are common. The percentage is of one axis, not of the image's area. It is the same for every 16:9 slot, because a cover fit scales uniformly. And it describes what the slot hides, not anything done to your file — the strip below the mockups shows it whole.
The near miss: why 1000×562 is "not 16:9"
Export at 1000 px wide and the honest 16:9 height is 562.5 px — not a whole pixel, so no export dialog can produce it. Either neighbour reports a sliver: 1000×562 simplifies to 500:281 and hides 0.1% of its width; 1000×563 simplifies to 1000:563 and hides 0.1% of its height. That is a fraction of a pixel at every preview size, reported only because the verdict is exact rather than approximate. A width that divides evenly by 16 — 1280 gives 720 with no rounding — avoids it; the aspect-ratio math guide lists the others.
The legibility strip
Below the mockups, the strip shows the same image at 120px, 168px, 246px wide. Unlike the slots, it sets only
the width and lets the height follow the image's own proportions, so nothing is cropped there — a
1:1 image appears square. The widths are not arbitrary: 120 px matches the smallest size YouTube stores for effectively every public video (default,
120×90), and 168 px matches the suggested / sidebar row while 246 px matches the search result row above.
The strip measures nothing. Your browser scales the image down with its ordinary resampling — no sharpening, no enhancement — and the only question it answers is whether what you put in the image can still be made out at that width. The widths are CSS pixels, the same unit the tester's slots use. If it cannot be read at 120 CSS px here, it cannot be read at 120 CSS px on this screen.
The grayscale toggle
The checkbox applies a grayscale filter to every preview and strip image at once, in the page, without touching the file. Hue is removed; lightness stays. Regions that were distinct only because they differed in hue merge; regions that differ in lightness stay separate. That is the entire mechanism — no score, no threshold, no number — and it applies to both slots at once.
A/B mode and the slot labels
Loading a second image into slot B makes every surface render both images with the same title, channel line, metadata, and badge, so the only variable is the image. Each item is captioned with its slot letter and a label. For uploads the label comes from the file name: a trailing extension — the final dot and the short run of letters or digits after it — is removed; underscores and hyphens become spaces; runs of whitespace collapse; anything longer than 40 characters is cut at 39 and given an ellipsis; and a name with nothing left becomes "Uploaded image". Pulled thumbnails are labelled with the video ID and the size key fetched.
| File name | Label shown |
|---|---|
my_thumbnail-v2_final.png | my thumbnail v2 final |
Final Cut - A.webp | Final Cut A |
cover.v2 | cover |
.png | Uploaded image |
thumbnail-episode-12-final-final-really-final-v3.png | thumbnail episode 12 final final really… |
.png becomes "Uploaded image" because nothing remains once the
extension is gone; the long name becomes "thumbnail episode 12 final final really…" — cut, not summarised. The
label is display-only, and the comparison is only that: two images under identical conditions.
The tester does not score them, rank them, or predict anything about either.
Pulling a thumbnail from a URL
Each slot's URL field runs the same parser as the downloader, so what the status line prints on
a bad paste is the parser's own message rather than a generic error. A watch link carrying a
timestamp, a youtu.be share link carrying its tracking string, and the bare ID —
https://www.youtube.com/watch?v=jNQXAC9IVRw&t=42s, https://youtu.be/jNQXAC9IVRw?si=share-token, and
jNQXAC9IVRw — all resolve to jNQXAC9IVRw; the extras are
ignored, not rejected. A playlist link is rejected as playlist-url — "That is a playlist link, not a single video. Open a video in the playlist and paste its URL." — and a lookalike host such as https://youtube.com.evil.example/watch?v=jNQXAC9IVRw as not-a-youtube-url — "That is not a YouTube link. This tool reads youtube.com and youtu.be URLs (or a bare video ID)." The matrix below runs 18 pasted forms through the parser
at build time: the 9 forms it accepts, each checked to resolve to the same ID,
and 9 of the ways it refuses, each with the code the build asserted and the message
the status line prints word for word. The
tester page walks the parser's decision order and names
the code each branch returns; every rejection the parser can produce, and the awkward variants it
normalizes before deciding, are tabulated on the methodology page.
| What was pasted | Input | Verdict | ID extracted, or the message printed |
|---|---|---|---|
| watch?v= link carrying a timestamp | https://www.youtube.com/watch?v=jNQXAC9IVRw&t=42s | accepted | jNQXAC9IVRw |
| youtu.be share link carrying its tracking string | https://youtu.be/jNQXAC9IVRw?si=share-token | accepted | jNQXAC9IVRw |
| Shorts link | https://www.youtube.com/shorts/jNQXAC9IVRw | accepted | jNQXAC9IVRw |
| Embed address | https://www.youtube.com/embed/jNQXAC9IVRw | accepted | jNQXAC9IVRw |
| /live/ link | https://www.youtube.com/live/jNQXAC9IVRw | accepted | jNQXAC9IVRw |
| Legacy /v/ path | https://www.youtube.com/v/jNQXAC9IVRw | accepted | jNQXAC9IVRw |
| Mobile host | https://m.youtube.com/watch?v=jNQXAC9IVRw | accepted | jNQXAC9IVRw |
| Link copied without its scheme | youtube.com/watch?v=jNQXAC9IVRw | accepted | jNQXAC9IVRw |
| Bare video ID | jNQXAC9IVRw | accepted | jNQXAC9IVRw |
| Playlist page | https://www.youtube.com/playlist?list=PLxyz | playlist-url | That is a playlist link, not a single video. Open a video in the playlist and paste its URL. |
| Watch link whose only parameter is a playlist | https://www.youtube.com/watch?list=PLxyz | playlist-url | That watch link points at a playlist without a specific video (no v= parameter). Open the video itself and paste its URL. |
| Channel handle | https://www.youtube.com/@examplechannel | channel-url | That is a channel link, not a video. Open one of the channel’s videos and paste that URL. |
| Lookalike host | https://youtube.com.evil.example/watch?v=jNQXAC9IVRw | not-a-youtube-url | That is not a YouTube link. This tool reads youtube.com and youtu.be URLs (or a bare video ID). |
| A sentence with the link inside it | watch this https://youtu.be/jNQXAC9IVRw | not-a-youtube-url | That does not look like a YouTube link or video ID — check for stray spaces. |
| A data: scheme carrying a YouTube hostname | data://www.youtube.com/watch?v=jNQXAC9IVRw | not-a-youtube-url | Only http(s) YouTube links are supported. |
| A YouTube page that is not a video | https://www.youtube.com/feed/subscriptions | unsupported-url | That YouTube link is not a video page this tool recognizes — paste a watch, youtu.be, Shorts, embed, or live URL. |
| An ID with a character outside the set | https://www.youtube.com/watch?v=jNQXAC9IV.w | invalid-video-id | That link does not contain a valid video ID — YouTube IDs are exactly 11 letters, digits, hyphens, or underscores. |
| Nothing, or spaces only | — | empty-input | Paste a YouTube video link or an 11-character video ID. |
With a valid ID, the tester fetches the stored sizes largest first — maxresdefault → sddefault → hqdefault — skipping the
two smallest (default and mqdefault). A size is passed over when the fetch
returns a non-ok status or the bytes decode to a placeholder-sized image; the decision on the
decoded bytes is the same pure classification the downloader uses. The engine would classify a
request for maxresdefault (1280×720) that comes back with a
non-ok status as missing — the size was never generated — but the tester skips such
a response before classifying, so that verdict never reaches a status line here. The same request
that comes back ok but decodes to 120×90 is classified missing: that is the placeholder guard, in case a placeholder ever arrives with an ok status. And a 120×90 decode for default is available, because the guard asks whether the decoded width is both smaller than the width requested and
no wider than the placeholder (120 px); for the smallest stored size the first test
fails, since 120 px is that size's real width. The full ladder, with each frame's
address, shape, and crop, is tabulated on the
tester page.
The consequence: maxresdefault (1280×720) exists only
for some uploads. When it does not, the tester lands on one of sddefault or hqdefault, each of which
YouTube stores in a 4:3 frame — so the status line reports 25% of the height hidden in 16:9 slots. That is the stored frame's shape, not a defect
in the artwork;
why maxresdefault is missing covers the rest.
One more edge: if something in your environment blocks the fetch, the tester still shows the image
straight from its YouTube address, but nothing was decoded, so the status line then carries the size
the engine expects for that key, not a measured one. Why the fetch normally works is documented on
the methodology page.
What the tester does not measure
The boundary deserves stating plainly. The tester does not measure clicks, views, watch time, ranking, or anything about how a thumbnail will do once published; no readout is a proxy for any of those. It does not check the upload rules — minimum width, file-size limits, accepted formats — which live on the size guide with their citation to Google's help documentation (verified July 25, 2026). It does not mark the typical overlay zones; that is the safe-area checker on the same page, and safe areas, explained covers them. It does not enhance, sharpen, or re-encode anything. And it sends nothing anywhere: uploads become in-memory object URLs in your tab, pulled thumbnails are fetched by your own browser directly from YouTube, and both are discarded when you close the page.
Frequently asked questions
What does the percentage in the status line mean?
The share of one axis — width or height, the line says which — that a 16:9 cover fit hides. It is not a share of the image's area, and it is the same in every 16:9 slot. A square 1080×1080 export reports 43.8% of its height hidden; a 2560×1080 banner reports 25% of its width.
Why is 1000×562 reported as “not 16:9” when it looks right?
Because the test is exact integer arithmetic (width × 9 must equal height × 16), and 1000 wide at 16:9 wants 562.5 px of height — not a whole pixel. 1000×562 reports 0.1% of its width hidden; 1000×563 reports 0.1% of its height. A width divisible by 16 (1280 → 720) avoids it.
Are the four preview sizes the sizes YouTube actually uses?
They are honest current typicals — 320×180, 168×94, 246×138, 160×90 — not a specification; platforms shift them a few pixels with every redesign. Two slots are exactly 16:9; the other two cannot be at their widths (168 px wide wants 94.5 px of height), so they sit within a pixel of it.
Why is the legibility strip not cropped when the mockups are?
The strip sets only the width (120px, 168px, 246px) and lets the height follow the image's own proportions, so it never crops. The mockup slots are fixed 16:9 boxes with a cover fit, so they do. The strip answers “is this readable at this width”; the mockups answer “what does the slot hide”.
Why did “Pull thumbnail” give me a 640×480 image with a crop warning?
The pull tries maxresdefault → sddefault → hqdefault, largest first, skipping any size that fails the HTTP check or decodes to the placeholder. When the largest was never generated, the tester lands on one of sddefault or hqdefault, each of which YouTube stores in a 4:3 frame — so the status line reports 25% of the height hidden. That is the stored frame's shape, not a fault in the video.
Why is my file name shortened in the A/B labels?
The label is derived from the file name: extension stripped, underscores and hyphens turned to spaces, repeated spaces collapsed, and anything longer than 40 characters cut with an ellipsis. A name with nothing left becomes “Uploaded image”. The label is display-only.
Every figure in this guide is computed at build time by the tester's own module, and images you load into the tester are processed locally and never transmitted. The preview sizes and crop math come from the same tested module documented on the methodology page.