How to Download a YouTube Thumbnail from a URL
Extract a YouTube video ID, build its thumbnail URL, download the best available size, and automate the process with Python, Node.js, or cURL.
Short answer: extract the YouTube video ID, then open https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg. Replace VIDEO_ID with the ID from the video URL and save the image. If the largest file is unavailable, try sddefault.jpg, hqdefault.jpg, mqdefault.jpg, or default.jpg.
1. Build a thumbnail URL from a YouTube link
YouTube thumbnail URLs use the video ID rather than the complete watch URL.
| URL form | Where to find the ID |
|---|---|
youtube.com/watch?v=VIDEO_ID |
Value after v= |
youtu.be/VIDEO_ID |
First path segment |
youtube.com/shorts/VIDEO_ID |
Segment after /shorts/ |
youtube.com/embed/VIDEO_ID |
Segment after /embed/ |
https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg
You can also use the commonly used i.ytimg.com host:
https://i.ytimg.com/vi/VIDEO_ID/maxresdefault.jpg
Open the resulting address in a browser, right-click the image, and choose Save image as. This downloads the thumbnail without downloading the video.
2. Choose the best available variant
| Filename | Typical use | Availability |
|---|---|---|
maxresdefault.jpg |
Largest standard variant, up to 1280×720 | Only some videos |
sddefault.jpg |
Standard-size fallback | Not guaranteed |
hqdefault.jpg |
High-quality fallback | Common |
mqdefault.jpg |
Medium-quality fallback | Common |
default.jpg |
Small default image, typically 120×90 | Common |
0.jpg, 1.jpg, 2.jpg, 3.jpg |
Generated frame variants | Depends on the video |
Google’s YouTube thumbnails documentation names the API sizes default, medium, high, standard, and maxres. Max-resolution thumbnails exist only for some videos, and dimensions can vary by resource.
3. Manual download
- Copy the YouTube video URL.
- Extract the ID from
v=,youtu.be/,/shorts/, or/embed/. - Insert it into the
img.youtube.comtemplate. - Open the image URL and confirm it is correct.
- Save the image from your browser.
- If
maxresdefault.jpgfails, try the fallback filenames in order.
This is the simplest approach for a one-off download.
4. Automate the download
Python
from urllib.parse import urlparse, parse_qs
import requests
variants = ['maxresdefault', 'sddefault', 'hqdefault', 'mqdefault', 'default']
def get_video_id(link):
parsed = urlparse(link)
host = parsed.netloc.lower().split(':')[0]
parts = [p for p in parsed.path.split('/') if p]
if host.endswith('youtu.be'):
return parts[0] if parts else None
if parts and parts[0] in {'shorts', 'embed', 'live'}:
return parts[1] if len(parts) > 1 else None
return parse_qs(parsed.query).get('v', [None])[0]
link = input('YouTube URL: ').strip()
video_id = get_video_id(link)
if not video_id:
raise SystemExit('Could not find a video ID')
for variant in variants:
url = f'https://img.youtube.com/vi/{video_id}/{variant}.jpg'
response = requests.get(url, timeout=30)
if response.ok and response.headers.get('content-type', '').startswith('image/'):
with open(f'{video_id}-{variant}.jpg', 'wb') as file:
file.write(response.content)
print(f'Saved {variant}: {url}')
break
else:
raise SystemExit('No thumbnail variant was available')
Node.js 18+
import { writeFile } from 'node:fs/promises';
const input = process.argv[2];
if (!input) throw new Error('Usage: node thumb.mjs YOUTUBE_URL');
const url = new URL(input);
const host = url.hostname.toLowerCase();
const parts = url.pathname.split('/').filter(Boolean);
let id;
if (host.endsWith('youtu.be')) id = parts[0];
else if (['shorts', 'embed', 'live'].includes(parts[0])) id = parts[1];
else id = url.searchParams.get('v');
if (!id) throw new Error('Could not find a video ID');
for (const variant of ['maxresdefault', 'sddefault', 'hqdefault', 'mqdefault', 'default']) {
const thumbnail = `https://img.youtube.com/vi/${id}/${variant}.jpg`;
const response = await fetch(thumbnail);
const type = response.headers.get('content-type') || '';
if (response.ok && type.startsWith('image/')) {
await writeFile(`${id}-${variant}.jpg`, Buffer.from(await response.arrayBuffer()));
console.log(`Saved ${variant}: ${thumbnail}`);
break;
}
}
cURL
curl -fL 'https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg' -o thumbnail.jpg
Use a fallback by changing the final filename:
curl -fL 'https://img.youtube.com/vi/VIDEO_ID/hqdefault.jpg' -o thumbnail.jpg
5. Use the YouTube Data API when dimensions matter
The direct URL method guesses filenames. For a catalog or batch pipeline, the YouTube Data API returns the available snippet.thumbnails entries, including URL, width, and height when supplied. Select the largest available entry instead of assuming maxres exists.
curl -G 'https://www.googleapis.com/youtube/v3/videos' \
--data-urlencode 'part=snippet' \
--data-urlencode 'id=VIDEO_ID' \
--data-urlencode 'key=YOUR_YOUTUBE_API_KEY'
In application code, inspect the returned keys and sort available images by width * height. The Data API has its own credentials and quota requirements.
6. Edge cases
- Playlist links: use the
vparameter fromwatch?v=ID&list=.... - Tracking parameters: ignore everything except the video ID.
- Mobile URLs:
m.youtube.com/watch?v=IDuses the same rule. - Live streams: use the ID in the watch URL; available sizes can differ while a stream is live.
- Private, removed, or invalid videos: a normal thumbnail may not be available.
- Older uploads: max-resolution files may not have been generated.
- Dimensions: documented sizes are typical values, not guarantees for every upload.
7. Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| 404 or failed download | Wrong ID or unavailable variant | Re-extract the ID and try sddefault, hqdefault, and smaller fallbacks. |
| Image is unexpectedly small | A low-resolution filename was selected | Try maxresdefault.jpg first, then sddefault.jpg. |
| Wrong video | A playlist or tracking value was copied | Use only the video ID from v or the path. |
| HTML saved as JPG | Redirect or non-image response | Follow redirects and validate the Content-Type header. |
| API returns no item | Private, removed, or invalid video | Verify that the video opens and check the ID and API key. |
| API quota error | Google Cloud quota or credentials | Use a direct image URL for simple jobs or resolve the project quota and key settings. |
8. Performance, reliability, and cost
- For one image, constructing the direct URL is fastest.
- For batches, parse IDs once, try variants in order, validate the content type, and record the successful variant.
- Cache files by video ID and variant to avoid repeated downloads.
- Retry transient network errors with a short backoff, but stop retrying a variant that is genuinely unavailable.
- Use API metadata when exact dimensions are important.
- Direct thumbnail URLs avoid downloading the video. The Data API uses its own quota model.
9. Or skip the browser setup
ScreenshotNeo can capture a URL with one GET request when you need a normalized PNG, JPEG, WebP, or PDF response. It removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing state. Its MCP server lets Claude, Cursor, and other MCP clients take screenshots.
See the ScreenshotNeo API documentation for configuration options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.
10. Check reuse rights before publishing
Downloading an image does not grant permission to republish it. Obtain the creator’s permission or confirm an applicable license or other lawful basis before using a thumbnail on a website, in an application, or in marketing. Review YouTube’s thumbnail policy as well.
11. FAQ
What is the maxresdefault URL?
https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg, with the actual video ID substituted. It is the largest standard variant when available.
Can I download a thumbnail without the API?
Yes. Direct image URLs work for manual downloads and scripts. The API is useful when you need the available URLs and dimensions returned programmatically.
Why does maxresdefault fail?
Max-resolution thumbnails exist only for some videos. Try sddefault, hqdefault, mqdefault, or default.
Can I publish the downloaded image?
Only if you have permission, a suitable license, or another lawful reuse basis.


