Thumbnail Tester & Previewer
A thumbnail that looks great at 1280×720 in your editor has to survive at 120 pixels next to autoplay and ads. Upload your design — or pull a video's current thumbnail — and see it at the sizes viewers actually meet it, before you publish.
Preview your thumbnail
Everything stays in your browser. Load a second design into slot B for a side-by-side A/B comparison.
What the tester actually does
When you choose a file, your browser decodes it locally to learn its pixel width and height, then displays it from an in-memory object URL. Nothing is resampled, analysed, or sent anywhere: the same bytes are drawn into each preview at a fixed display size. When you paste a link instead, the same parser and thumbnail-set engine that power the downloader turn it into an 11-character video ID and a list of image addresses, your browser fetches the largest one directly from YouTube, and the placeholder check runs before anything is shown. Either way, every loaded image is then rendered in 4 surfaces — Home grid card (desktop) at 320×180px, Suggested / sidebar row at 168×94px, Search result row at 246×138px, Mobile list row at 160×90px — and in a legibility strip at 120, 168, 246 pixels wide, with your title, channel name, meta line, and duration badge around it, because a thumbnail is never displayed in isolation.
Reading the result for the first time? The guide How to read the thumbnail tester owns the worked examples — the status line readout by readout, the near-miss export sizes, and the filename label rules with sample names — and the rest of the site's background reading is in the guides index. This page explains the mechanism those examples come from: what is fetched, what is decoded, what is computed, and where the tool stops.
The preview surfaces: typical, not a spec
The 4 slots are rendered at true display sizes — the CSS pixel sizes video
platforms typically use for each surface. They move a few pixels with every redesign, so the engine
labels them honest current typicals and this page repeats the label: representative, never exact.
Each slot is a fixed box of exactly that width and height, and your image is drawn inside it at
that size, so what you see is the detail that survives inside that pixel budget, not a resampled
file. The table below adds the engine's own arithmetic. The simplified ratio comes from the same
describeRatio function the tool uses on your upload, and the last column asks the aspect
engine what exact 16:9 would need at each width.
2 of the 4 typicals cannot be exactly 16:9, because
whole pixels cannot land on a fractional height — the engine reports the exact value and the rounding
rather than hiding it.
| Surface | Typical size | Ratio | Exact 16:9 height at that width |
|---|---|---|---|
| Home grid card (desktop) | 320×180px | 16:9 (1.778) | 180 — exact |
| Suggested / sidebar row | 168×94px | 84:47 (1.787) | 94.5 — no whole pixel; nearest is 95 |
| Search result row | 246×138px | 41:23 (1.783) | 138.375 — no whole pixel; nearest is 138 |
| Mobile list row | 160×90px | 16:9 (1.778) | 90 — exact |
The legibility strip
Below the mockups, the strip shows the same image at 120px, 168px, 246px wide — from the width of the smallest size YouTube stores (120×90) up to the width of the search result row typical (246×138); both ends are pinned to those engine constants when the page is built. The strip fixes only the width; the height follows from the image's own ratio, so a 16:9 image comes out 67.5px tall at 120px, 94.5px tall at 168px, 138.375px tall at 246px — fractional where the arithmetic is fractional, which the browser handles. Nothing is measured here. The strip exists so you can see, rather than guess, which parts of the image remain distinguishable between 120 and 246 pixels, and the grayscale toggle applies to it as well.
Pulling a thumbnail from a video link
The URL box runs the same parser as the downloader, and the parser works in a fixed order
rather than by pattern-matching the whole string. The input is trimmed, and an empty box is
refused as empty-input. If what remains is exactly an 11-character video ID —
letters, digits, hyphen, underscore — it is accepted as a bare ID with no URL machinery at
all. Anything with whitespace inside is refused as not-a-youtube-url, because it is
neither a link nor an ID. The text is then read as a web address — a missing https:// is supplied, so a copied youtube.com/… without its scheme still parses — and only
http and https schemes survive: a javascript: address can
carry a convincing hostname, and it is refused as not-a-youtube-url before the hostname
is even looked at. The hostname must be one YouTube serves video pages from. A
youtu.be share link takes the first path segment as its ID; a lookalike domain such
as youtube.com.evil.example is refused as not-a-youtube-url, not
treated as YouTube. On a genuine host the first path segment decides the rest: channel paths
are refused as channel-url, a playlist page as playlist-url,
a watch link that carries list= but no v= as
playlist-url, and an embed/videoseries playlist embed as playlist-url; a
watch link yields its v= value, and Shorts, embed, /live/, and legacy /v/ paths yield the segment after them. A YouTube path the parser does
not recognise is unsupported-url, and every candidate ID, from whichever
branch, is validated against the exact character set and length, so invalid-video-id
is the answer for a too-short ID inside a link (a bare ID that is too short never reaches this step
— it fails the ID pattern, is read as an address, and is refused as not-a-youtube-url, as the methodology table shows). Each of those codes was produced by running the parser
when this page was built, and the 6 accepted forms — watch?v= with extra parameters, youtu.be with a tracking string, Shorts without a scheme, embed, /live/, a bare ID — were checked to resolve to one and the same ID. The complete rejection table — every rejection
the engine can produce, with the message the status line prints word for word — is on the
methodology page.
From a valid ID the engine derives one address per stored size, and the tester walks them
largest-first: maxresdefault → sddefault → hqdefault. It stops at hqdefault, which exists for effectively
every public video, so the 2 smallest sizes are never requested. The downloader
needs a verdict for every size, because each one gets its own button or a "not available for this
video" label; the tester needs one image, so it stops at the first size that passes. Whichever frame
you end up with, the crop report treats it like any other upload — and the fallbacks are stored
in
4:3 frames, so if the largest size is missing for that video the status line will say
the image is not 16:9 and quantify the crop.
| Order | Size key | Frame | Ratio | Cover crop in a 16:9 slot | Address |
|---|---|---|---|---|---|
| 1 | maxresdefault | 1280×720 | 16:9 | none | https://img.youtube.com/vi/jNQXAC9IVRw/maxresdefault.jpg |
| 2 | sddefault | 640×480 | 4:3 | 25% of height hidden | https://img.youtube.com/vi/jNQXAC9IVRw/sddefault.jpg |
| 3 | hqdefault | 480×360 | 4:3 | 25% of height hidden | https://img.youtube.com/vi/jNQXAC9IVRw/hqdefault.jpg |
That the fetch works at all is not a given. A page can only read image bytes from another
domain when that domain's server explicitly allows it (CORS), and YouTube's image server sends
Access-Control-Allow-Origin: * on thumbnail responses — verified empirically, as the
methodology page records. That header is what lets your browser fetch
the image, decode it, and run the check below; without it the tester could display the image but
never measure it. The request goes from your browser straight to YouTube's image server, the same
request it would make while you browse YouTube, and this site's servers never see the link.
A missing size does not fail cleanly on YouTube's side: the answer is HTTP 404 with a gray
120×90 placeholder as its body, which a plain
<img> renders without complaint. The tester reads the two signals the methodology
page describes, in order. A response whose status is not OK is skipped outright — nothing is decoded,
and the ladder moves to the next size. An OK response is decoded in your browser to learn its real
pixel width and height, and those dimensions are handed, with the status flag set, to the same pure
classifier the downloader uses. Asking for
maxresdefault and decoding 1280×720 is classified
available, and the ladder stops there; asking for maxresdefault
and decoding 120×90 is classified
missing, and any answer other than available sends
the ladder on to the next size. The width test is relative to the size requested rather than an
absolute threshold, because default really is
120×90: the classifier calls a 120-pixel decode at
that size available. That size is never in the tester's ladder, so
the distinction matters to the downloader rather than here — as do the classifier's inputs the
tester never supplies: a failed status (classified missing) and bytes
that will not decode (classified undecodable), which the downloader
needs in order to label every size. The tester skips a non-OK response before classifying, and
a body that will not decode drops it into the fallback path described under
Where the tool stops. The classifier's full matrix is on the methodology
page; the guide walks through the three verdicts a status line usually shows.
How the crop report is computed
The status line under each slot reports the image's pixel size, its simplified ratio, and what a 16:9 "cover" fit hides. The 16:9 test is exact integer arithmetic — width × 9 must equal height × 16 — and the crop is geometry, not opinion: an image wider than 16:9 is scaled to the slot's height and loses width at the sides; a taller one is scaled to the slot's width and loses height at the top and bottom. The percentage is the share of that axis outside the slot, rounded to one decimal. Every figure below comes from the engine for the listed input.
| Upload | Pixels | Ratio | Fits 16:9 | Hidden in a 16:9 slot |
|---|---|---|---|---|
| Full-HD export | 1920×1080 | 16:9 (1.778) | yes | nothing |
| Resolution guidance (size guide) | 3840×2160 | 16:9 (1.778) | yes | nothing |
| maxresdefault frame | 1280×720 | 16:9 (1.778) | yes | nothing |
| sddefault frame | 640×480 | 4:3 (1.333) | no | 25% of height |
| hqdefault frame | 480×360 | 4:3 (1.333) | no | 25% of height |
| Square | 1080×1080 | 1:1 (1.000) | no | 43.8% of height |
| Vertical | 1080×1920 | 9:16 (0.563) | no | 68.4% of height |
| Ultra-wide | 2560×1080 | 64:27 (2.370) | no | 25% of width |
| Wide share card | 1200×630 | 40:21 (1.905) | no | 6.7% of width |
The 16:9 target is not the tester's own choice. Google's help documentation recommends that shape — the size guide cites it to Google's "Add video thumbnails" article, checked on July 25, 2026 — which is why the slots and the crop report are built around that one ratio. The resolution-guidance row in the table takes its input from the size guide too, read from that page as it builds, so the figure is the one it cites to the same article on the same date rather than a claim of this page's own. The engine does not round an image into 16:9 that is not: the test has no tolerance, so an export one pixel off its exact height is reported as not 16:9 with the small crop that miss costs, and the guide walks through that near-miss case with the numbers. If you want the report to say "fits", pick a width the aspect calculator marks as exact. For a square upload the whole line reads: Loaded: my design — 1080×1080 (1:1); not 16:9 — about 43.8% of its height is hidden in 16:9 slots.
Filenames and labels
An upload is labelled by its filename so that A/B rows stay readable: the extension is stripped, hyphens and underscores become spaces, runs of whitespace collapse, and anything longer than 40 characters is cut with an ellipsis. A name that is only an extension falls back to a generic label. The filename never leaves your browser and is not part of any measurement — it is display text, derived by the same pure function the tool calls, and the guide runs sample filenames through it.
A thumbnail pulled from a link is labelled with its video ID and the size key that was
actually served, so an A/B row tells you whether you are looking at
maxresdefault or a fallback frame.
What is measured, and what is not
Measured: the decoded pixel width and height, the simplified ratio and its decimal, whether the image is exactly 16:9, and the axis and percentage a cover fit hides. Rendered but not measured: the image at each typical size, the strip, and the mockup text you typed. Not measured at all: any contrast score, any detection of text or faces, and anything about what happens after you publish — the tester makes no prediction, ranks nothing, and would be dishonest if it claimed to. The grayscale toggle is a display filter, not an analysis. The duration badge in the mockups is a rendered element placed by the stylesheet, not the overlay-zone arithmetic; if you want the zone geometry, the safe-area checker computes it from the same convention-not-spec module. For the home grid card (desktop) size of 320×180, that engine places the typical zones at: Duration badge (typical) 70×25px at (250, 155); Hover controls (typical) 51×54px at (269, 0); Watched-progress bar (typical) 320×9px at (0, 171). Those rects model a convention at typical proportions — YouTube publishes no overlay specification — which is why every label carries the word typical.
Where the tool stops
Sizes are CSS pixels; what you see is your browser's own scaling of the image at that size, not a downsampled copy you could export. If no size in the ladder passes the check, the status line reports that no thumbnail could be fetched for that video. A file that will not decode as an image, or that is over the tester's size cap, is refused with a message rather than shown broken. If the fetch itself is blocked in your environment, the tester degrades to a direct image address — the previews still render, but the placeholder check cannot run and the reported size is the nominal one for that variant, not a decoded measurement. And the title, channel, and meta line are yours to type: they change what surrounds the image and nothing else.
A/B without self-deception
When you compare two designs, keep everything else identical — same title, same metadata, same surfaces. That is exactly what slot B does: both images are rendered at the same sizes, next to the same text, in the same order, so the only variable is the thumbnail itself. The tester does not score the pair or predict anything about them. What it gives you is the comparison at the sizes that matter, with the shrinking already done, so that the decision is made against the real display size rather than the editor's zoom level.
Why the mockups are generic on purpose
These previews are evocative of "a video platform" — neutral grays, no logo, no cloned iconography — because YouTube's interface and branding belong to YouTube. The pixel sizes, text truncation, and badge placement are what you need to evaluate a thumbnail, and none of that requires imitating anyone's trade dress. ThumbnailPro is not affiliated with YouTube or Google.
Frequently asked questions
Why do the mockups look like a video platform but not exactly like YouTube?
Deliberately. YouTube’s interface, logo, and exact iconography are YouTube’s property, so the previews use neutral, generic video-platform layouts at the same display sizes instead. What matters for judging a thumbnail — the pixel dimensions, the surrounding text, the duration badge covering a corner — is all there; the branding is not.
Are the preview sizes real?
They are honest current typicals: 320×180, 168×94, 246×138, 160×90 pixels for the grid, sidebar, search, and mobile surfaces. Platforms shuffle these by a few pixels with every redesign, so treat them as representative display sizes, not a specification.
What does the grayscale toggle actually do?
It applies a grayscale filter to every thumbnail image in the mockups, both A/B slots, and the legibility strip — and nothing else. No score is computed. Whatever still separates one region of your image from another with the color removed is a difference in lightness; whatever disappears was carried by hue alone. That is the entire check, and you read it by eye.
Why does my uploaded image get cropped in the previews?
The preview slots are 16:9, like the surfaces they stand in for. An image of another shape is fitted the way a “cover” fit does — scaled until it fills the slot, with the overflow on one axis hidden — and the status line names the axis and the percentage. A 4:3 frame such as 640×480 loses 25% of its height; a square one loses 43.8%. Export at exactly 16:9 — the shape Google’s help documentation recommends, verified July 25, 2026 on the size guide — at 1280×720 or larger, and nothing is hidden.
Is my image uploaded to a server?
No. The file is read by JavaScript in your tab, displayed from a local object URL, and discarded when you close the page. Nothing you upload leaves your device.
Can I compare two designs?
Yes — load a second image into slot B and every mockup renders both designs side by side with the same title and metadata, so the only variable is the thumbnail itself. The tester does not score or rank the two; it puts them at identical sizes next to identical text and leaves the judgement to you.
Which image do I get when I paste a video link?
The largest one YouTube actually serves for that video. The tester requests maxresdefault → sddefault → hqdefault in that order and keeps the first that passes the placeholder check; the ladder stops at hqdefault, which exists for effectively every public video, so the 2 smallest stored sizes (default at 120×90 and mqdefault at 320×180) are never requested. If only hqdefault exists you get a 480×360 image, which is 4:3 — and the crop report will say so.
What happens if my browser cannot fetch the image?
If the request itself fails — an extension or proxy interfering with it, for example — the tester falls back to showing the image straight from YouTube’s address in a plain image element. The previews still render, but on that path the tool cannot decode the bytes, so the status line reports the size YouTube lists for that variant rather than a measured one, and the placeholder check cannot run.
Images are processed locally and never transmitted. The preview sizes and crop math come from the same tested module documented on the methodology page.