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). |
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" />
}