Advanced

Thumbnail Strategy

How ytcn loads thumbnails and why it matters for perceived performance.

Three-phase lifecycle

ytcn uses a three-phase state machine to manage the player lifecycle. This eliminates the black flash that occurs when loading YouTube iframes directly.

PhaseWhat's visibleDuration
thumbnailCDN thumbnail + play button overlay< 100ms to first paint
loadingBlurred thumbnail + spinner1–3s (iframe initialization)
readyLive video with custom controlsRest of session

Thumbnail probing

The useThumbnail hook probes YouTube's CDN in priority order. It uses imperative Image() objects (not fetch) to avoid CORS issues.

thumbnail probing order
Priority 1: https://img.youtube.com/vi/{id}/maxresdefault.jpg  (1280×720)
Priority 2: https://img.youtube.com/vi/{id}/hqdefault.jpg       (480×360)
Priority 3: https://img.youtube.com/vi/{id}/mqdefault.jpg       (320×180)
Priority 4: https://img.youtube.com/vi/{id}/default.jpg          (120×90)

Why not just use maxresdefault?

Not all videos have a maxresdefault thumbnail. Videos uploaded in standard definition (480p or below) only have the lower-resolution options. The probing strategy ensures ytcn always shows the best available thumbnail without requiring the user to specify a URL.

Performance impact

Loading a thumbnail from YouTube's CDN is dramatically faster than loading the full iframe:

  • Thumbnail: ~20KB image, loads in under 100ms on broadband
  • YouTube iframe: ~500KB+ of JavaScript, 1–3 seconds to initialize

Custom thumbnails

If you want to use your own thumbnails instead of YouTube's CDN, bypass the hook and pass a URL directly:

custom-thumbnail.tsx
// Skip useThumbnail and provide your own
<img
  src="/my-custom-thumbnail.jpg"
  alt="Video thumbnail"
  className="absolute inset-0 w-full h-full object-cover"
/>