Thumbnail URL API
The thumbnail API is a set of URL shapes served from the apex domain
vumbnail.com. There is no JSON API and no key — the path encodes the request
and the response is an image.
Behavior
Section titled “Behavior”A user takes a video and rewrites its URL as a Vumbnail path:
- YouTube
https://www.youtube.com/watch?v=zFJ3yNVQ3v4→https://vumbnail.com/zFJ3yNVQ3v4.jpg - Vimeo
https://vimeo.com/637615910→https://vumbnail.com/637615910.jpg
The Worker parses the path into a provider, video ID, optional password, and
optional size, resolves the poster frame, and returns it as image/jpeg. The
same path is stable and cacheable, so it can be dropped into an <img> tag, an
Open Graph tag, or any client that fetches a URL.
Supported path shapes
Section titled “Supported path shapes”| Path | Meaning |
|---|---|
/<id>.jpg, /<id>.jpeg, /<id> | Default thumbnail (extension optional, case-insensitive) |
/<id>_<size>.jpg | A specific size variant, e.g. /zFJ3yNVQ3v4_hqdefault.jpg |
/<numericId>.jpg | Vimeo (all-numeric IDs route to Vimeo; alphanumeric route to YouTube) |
/<id>:<password>.jpg | Password-protected Vimeo video |
/playlist?list=<playlistId>.jpg | The first video of a YouTube playlist |
- Provider detection is by ID shape: all-numeric → Vimeo, otherwise YouTube.
- Default size: YouTube resolves to
hqdefaultunless a size is given. - ID canonicalization: a trailing numeric suffix is treated as a size hint
and stripped for the cache key (
1101804103_123456.jpgand1101804103_.jpgboth cache as1101804103). Non-numeric suffixes are preserved.
Inputs & outputs
Section titled “Inputs & outputs”Inputs (all from the HTTP request — there is no request body):
- Path — encodes provider, video ID, optional
:password, optional_size, optional.jpg/.jpegextension. - Query —
?list=for playlists; legacy?h=<password>for Vimeo (see Redirects & compatibility);?key=<apiKey>for paid bypass;?debug/?_debugfor diagnostic headers. - Headers —
Referer(drives the watermark decision),CF-Connecting-IP,User-Agent, and an optionalX-Vumbnail-Keyheader for paid bypass.
Outputs:
- A
200image/jpegbody — the clean or watermarked poster frame. Content-Disposition: inlinewith a filename hint.Cache-Controlheaders tuned per variant (clean vs. watermarked vs. fallback).- Redirects (
302/307) for the compatibility cases in Redirects & compatibility. - In debug mode, a set of
X-Thumbnail-*headers describing the decision.
States & edge cases
Section titled “States & edge cases”- Unknown / deleted video — resolves to the shared
error.jpgfallback, served200so the<img>never breaks; the failure is negatively cached. - Password-protected Vimeo — if the password is supplied and valid, the
poster is returned; otherwise a shared
locked.jpggraphic is served with a restriction header. - Playlist — known playlists are redirected to a mapped video ID; unknown playlists are resolved to their first video via oEmbed or an external resolver (see Redirects & compatibility).
- Unsupported but thumbnail-shaped path (8+ char id + optional suffix,
.jpg/.jpeg) — routed to anerror.jpgfallback rather than a 404. - Non-thumbnail path — passed through to the marketing site service binding
(
astro.vumbnail.com), or returns a404text response (debug JSON if?debugis set). - Provider slow / rate-limiting — served from cache if warm; otherwise the Vimeo relay or negative cache absorbs the failure. The viewer never waits on a hung upstream beyond the resolver timeout.
Data shape
Section titled “Data shape”The parsed request that the rest of the pipeline operates on:
type ThumbnailRequest = { provider: "youtube" | "vimeo" videoId: string // canonical id used for the cache key password?: string // Vimeo password, from ":pw" path or legacy ?h= size?: string // e.g. "hqdefault", "sddefault"; provider default if absent extension: "jpg" | "jpeg" | "" playlistId?: string // present for /playlist?list=... requests}
// What the client ultimately receives:type ThumbnailResponse = { status: 200 | 302 | 307 | 404 contentType: "image/jpeg" | "text/plain" variant: "clean" | "wm" | "fallback-error" | "fallback-locked" body: ArrayBuffer // the JPEG bytes}Open questions
Section titled “Open questions”- Animated and non-JPEG output. Short animated previews exist behind a flag
(see Animated thumbnails); WebP/AVIF output
is not currently offered. Whether to expose them through the same path shape
(e.g.
.gif,.webp) is undecided. - Explicit size vocabulary. The set of accepted
_sizetokens per provider is provider-derived rather than a documented, stable list. A published size vocabulary is not yet committed to. - See the global Open questions page for cross-cutting items.