Hook
useThumbnail
Resolves the highest available YouTube thumbnail for a video ID.
How it works
Probes thumbnail URLs in priority order using imperative Image() objects. Stops at the first URL that loads successfully. Resets automatically when videoId changes.
Priority order
| Priority | URL | Resolution | Always exists? |
|---|---|---|---|
| 1 | maxresdefault.jpg | 1280×720 | No (720p+ uploads only) |
| 2 | hqdefault.jpg | 480×360 | Almost always |
| 3 | mqdefault.jpg | 320×180 | Yes |
| 4 | default.jpg | 120×90 | Yes |
Returns
| Prop | Type | Default | Description |
|---|---|---|---|
| thumbnailUrl | string | null | — | Best available thumbnail URL, or null while still loading. |
| thumbnailLoaded | boolean | — | True when the thumbnail image has loaded successfully. |
| thumbnailFailed | boolean | — | True when all thumbnail URLs failed to load (private video). |
thumbnailUrl
string | null
Best available thumbnail URL, or null while still loading.
thumbnailLoaded
boolean
True when the thumbnail image has loaded successfully.
thumbnailFailed
boolean
True when all thumbnail URLs failed to load (private video).
Handling failures
failure-handling.tsx
const { thumbnailUrl, thumbnailFailed } = useThumbnail(videoId)
// If thumbnail failed, skip directly to iframe loading
if (thumbnailFailed) {
setPhase("loading")
initializeIframe()
}
// Otherwise show the thumbnail while loading
if (thumbnailUrl) {
return <img src={thumbnailUrl} alt="Video thumbnail" />
}