February 14, 2026 ยท 11 min read
Website Thumbnail Generator API: Generate Website Previews at Scale
Website thumbnails are everywhere โ link previews in chat apps, directory listings, portfolio showcases, search results, and bookmarking tools. Generating these website preview images at scale requires a reliable thumbnail generator API that can handle thousands of URLs without breaking a sweat.
In this guide, we'll show you how to build a website thumbnail generation system using SnapAPI, from basic captures to advanced caching and optimization strategies.
๐ผ๏ธ Generate Thumbnails Instantly
200 free thumbnails/month. Multiple sizes and formats. No credit card required.
Get Free API Key โWhat Are Website Thumbnails?
A website thumbnail is a small preview image of a webpage. Think of the preview cards you see when sharing a link on Slack, Twitter, or LinkedIn. These visual previews help users decide whether to click through, dramatically improving engagement rates.
Common use cases include:
- Link previews โ Show visual previews of shared URLs in chat apps and messaging platforms
- Website directories โ Display thumbnail previews in curated link collections and catalogs
- Portfolio showcases โ Show live previews of web projects and designs
- Bookmarking apps โ Visual bookmarks are far more browsable than text-only lists
- Search results โ Some search engines and tools show site previews alongside results
- Social media cards โ Generate preview images for sharing on social platforms
- SEO monitoring โ Track visual changes to competitor websites over time
Quick Start: Generate a Website Thumbnail
Generate a thumbnail of any website with a single API call:
curl "https://api.snapapi.pics/v1/screenshot?\
url=https://github.com&\
width=1280&\
height=800&\
format=webp&\
quality=80" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o github-thumbnail.webp
This captures a 1280x800 viewport screenshot in WebP format. For thumbnails, WebP offers the best quality-to-size ratio, typically 30-50% smaller than JPEG at equivalent quality.
Generating Smaller Thumbnails
For directory listings and grids, you often need smaller images. Use the width parameter to control the output size:
# Small thumbnail (400px wide)
curl "https://api.snapapi.pics/v1/screenshot?\
url=https://github.com&\
width=400&\
height=300&\
format=webp&\
quality=75" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o thumbnail-small.webp
# Medium thumbnail (800px wide)
curl "https://api.snapapi.pics/v1/screenshot?\
url=https://github.com&\
width=800&\
height=600&\
format=webp&\
quality=80" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o thumbnail-medium.webp
Building a Thumbnail Generation Service
Let's build a complete thumbnail service that generates, caches, and serves website previews. This is the pattern used by apps like Notion, Raindrop.io, and Pocket.
Node.js Thumbnail Service
const express = require('express');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const app = express();
const CACHE_DIR = './thumbnails';
const SNAPAPI_KEY = process.env.SNAPAPI_KEY;
// Ensure cache directory exists
if (!fs.existsSync(CACHE_DIR)) fs.mkdirSync(CACHE_DIR, { recursive: true });
// Generate a cache key from URL and size
function cacheKey(url, width, height) {
const hash = crypto.createHash('md5').update(`${url}-${width}-${height}`).digest('hex');
return path.join(CACHE_DIR, `${hash}.webp`);
}
// Thumbnail endpoint
app.get('/thumbnail', async (req, res) => {
const { url, width = 800, height = 600 } = req.query;
if (!url) return res.status(400).json({ error: 'URL required' });
const cachePath = cacheKey(url, width, height);
// Serve from cache if available
if (fs.existsSync(cachePath)) {
const stat = fs.statSync(cachePath);
const age = Date.now() - stat.mtimeMs;
// Cache valid for 24 hours
if (age < 24 * 60 * 60 * 1000) {
res.setHeader('Content-Type', 'image/webp');
res.setHeader('Cache-Control', 'public, max-age=86400');
res.setHeader('X-Cache', 'HIT');
return fs.createReadStream(cachePath).pipe(res);
}
}
// Generate new thumbnail
try {
const response = await fetch(
`https://api.snapapi.pics/v1/screenshot?` +
`url=${encodeURIComponent(url)}&width=${width}&height=${height}` +
`&format=webp&quality=80&block_ads=true`,
{ headers: { 'Authorization': `Bearer ${SNAPAPI_KEY}` } }
);
if (!response.ok) throw new Error(`API returned ${response.status}`);
const buffer = Buffer.from(await response.arrayBuffer());
// Save to cache
fs.writeFileSync(cachePath, buffer);
res.setHeader('Content-Type', 'image/webp');
res.setHeader('Cache-Control', 'public, max-age=86400');
res.setHeader('X-Cache', 'MISS');
res.send(buffer);
} catch (error) {
console.error('Thumbnail generation failed:', error.message);
res.status(500).json({ error: 'Failed to generate thumbnail' });
}
});
app.listen(3000, () => console.log('Thumbnail service running on :3000'));
This service generates thumbnails on-demand, caches them for 24 hours, and serves cached versions for repeat requests. In production, you'd want to replace the filesystem cache with S3 or a CDN.
Python Thumbnail Service
import hashlib
import os
import time
from flask import Flask, request, send_file, jsonify
import requests
import io
app = Flask(__name__)
CACHE_DIR = './thumbnails'
SNAPAPI_KEY = os.environ['SNAPAPI_KEY']
CACHE_TTL = 86400 # 24 hours
os.makedirs(CACHE_DIR, exist_ok=True)
def cache_path(url, width, height):
key = hashlib.md5(f"{url}-{width}-{height}".encode()).hexdigest()
return os.path.join(CACHE_DIR, f"{key}.webp")
@app.route('/thumbnail')
def thumbnail():
url = request.args.get('url')
width = request.args.get('width', 800, type=int)
height = request.args.get('height', 600, type=int)
if not url:
return jsonify(error='URL required'), 400
path = cache_path(url, width, height)
# Check cache
if os.path.exists(path):
age = time.time() - os.path.getmtime(path)
if age < CACHE_TTL:
return send_file(path, mimetype='image/webp')
# Generate thumbnail
response = requests.get(
'https://api.snapapi.pics/v1/screenshot',
params={
'url': url, 'width': width, 'height': height,
'format': 'webp', 'quality': 80, 'block_ads': True
},
headers={'Authorization': f'Bearer {SNAPAPI_KEY}'}
)
if response.status_code != 200:
return jsonify(error='Generation failed'), 500
# Cache and serve
with open(path, 'wb') as f:
f.write(response.content)
return send_file(io.BytesIO(response.content), mimetype='image/webp')
Optimization Strategies
1. Choose the Right Format
SnapAPI supports PNG, JPEG, WebP, and AVIF formats. For thumbnails, the choice matters:
- WebP โ Best all-around choice. 30-50% smaller than JPEG, supports transparency. 97% browser support in 2026.
- AVIF โ Smallest file sizes (up to 50% smaller than WebP) but slower to encode. SnapAPI is one of the few APIs supporting AVIF output.
- JPEG โ Universal compatibility but larger files. Use only if you need to support very old browsers.
- PNG โ Lossless quality but much larger files. Avoid for thumbnails unless you need pixel-perfect reproduction.
2. Viewport Size Strategy
The viewport you capture at affects both quality and cost. Here's a recommended strategy:
- Desktop preview: Capture at 1280x800, serve at 640x400 (retina-ready)
- Mobile preview: Capture at 375x812 (iPhone viewport)
- Social card: Capture at 1200x630 (OG image standard)
- Grid thumbnail: Capture at 800x600, serve at 400x300
3. Block Ads and Cookie Banners
Nothing ruins a thumbnail like a cookie consent popup covering half the page. Use SnapAPI's built-in ad and cookie banner blocking:
curl "https://api.snapapi.pics/v1/screenshot?\
url=https://example.com&\
block_ads=true&\
block_cookie_banners=true&\
width=1280&height=800&format=webp" \
-H "Authorization: Bearer YOUR_API_KEY" -o clean-thumbnail.webp
4. Dark Mode Thumbnails
Many websites support dark mode. Generate dark mode thumbnails for consistency with your own dark-themed UI:
curl "https://api.snapapi.pics/v1/screenshot?\
url=https://github.com&\
dark_mode=true&\
width=1280&height=800&format=webp" \
-H "Authorization: Bearer YOUR_API_KEY" -o dark-thumbnail.webp
5. Caching with CDN
For high-traffic applications, put your thumbnails behind a CDN. Generate once, serve millions of times:
// Upload to S3 after generation
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const s3 = new S3Client({ region: 'us-east-1' });
async function generateAndCache(url) {
const key = `thumbnails/${md5(url)}.webp`;
// Check if already cached in S3
try {
await s3.send(new HeadObjectCommand({ Bucket: 'my-thumbnails', Key: key }));
return `https://cdn.example.com/${key}`; // Already cached
} catch {}
// Generate via SnapAPI
const response = await fetch(
`https://api.snapapi.pics/v1/screenshot?url=${encodeURIComponent(url)}&format=webp&width=800&height=600`,
{ headers: { 'Authorization': `Bearer ${SNAPAPI_KEY}` } }
);
// Upload to S3
await s3.send(new PutObjectCommand({
Bucket: 'my-thumbnails',
Key: key,
Body: Buffer.from(await response.arrayBuffer()),
ContentType: 'image/webp',
CacheControl: 'public, max-age=604800' // 7 days
}));
return `https://cdn.example.com/${key}`;
}
Batch Thumbnail Generation
Need to generate thumbnails for hundreds of URLs at once? Here's a batch processing pattern:
// Batch generate with concurrency control
const pLimit = require('p-limit');
const limit = pLimit(10); // 10 concurrent requests
const urls = [
'https://github.com',
'https://stackoverflow.com',
'https://dev.to',
// ... hundreds more
];
const results = await Promise.allSettled(
urls.map(url => limit(async () => {
const response = await fetch(
`https://api.snapapi.pics/v1/screenshot?url=${encodeURIComponent(url)}&format=webp&width=800&height=600&quality=80`,
{ headers: { 'Authorization': `Bearer ${SNAPAPI_KEY}` } }
);
if (!response.ok) throw new Error(`Failed: ${url}`);
const filename = `thumbnails/${url.replace(/[^a-z0-9]/gi, '_')}.webp`;
fs.writeFileSync(filename, Buffer.from(await response.arrayBuffer()));
return { url, filename, status: 'success' };
}))
);
const succeeded = results.filter(r => r.status === 'fulfilled').length;
console.log(`Generated ${succeeded}/${urls.length} thumbnails`);
SnapAPI supports unlimited concurrent requests on all plans, so you can parallelize as aggressively as your application needs.
Link Preview Implementation
Building a link preview feature like Slack or Notion? Here's the full flow:
// 1. User pastes a URL in your app
// 2. Your backend generates a preview
async function generateLinkPreview(url) {
// Fetch metadata (title, description) via SnapAPI extract
const metaResponse = await fetch(
`https://api.snapapi.pics/v1/extract?url=${encodeURIComponent(url)}`,
{ headers: { 'Authorization': `Bearer ${SNAPAPI_KEY}` } }
);
const metadata = await metaResponse.json();
// Generate thumbnail
const imgResponse = await fetch(
`https://api.snapapi.pics/v1/screenshot?url=${encodeURIComponent(url)}&format=webp&width=800&height=600&quality=80&block_ads=true`,
{ headers: { 'Authorization': `Bearer ${SNAPAPI_KEY}` } }
);
const thumbnail = Buffer.from(await imgResponse.arrayBuffer());
return {
url,
title: metadata.title,
description: metadata.description,
thumbnail: thumbnail, // Save to storage and return URL
favicon: metadata.favicon
};
}
This combines SnapAPI's content extraction with screenshot generation for a complete link preview solution.
Comparison: SnapAPI vs. Other Thumbnail Services
Why choose SnapAPI for thumbnail generation? See our full screenshot API comparison for details, but here are the highlights for thumbnail-specific use:
- Format support: SnapAPI is the only API offering AVIF output โ the smallest thumbnails possible
- Speed: Sub-2-second captures mean thumbnails generate almost instantly
- Ad blocking: Built-in ad and cookie banner blocking produces cleaner thumbnails
- Dark mode: Native dark mode capture support for consistent UX
- Cost: At $2.90 per 1,000 thumbnails, it's the most affordable option โ see pricing
- Free tier: 200 free thumbnails/month to get started
๐ Start Generating Website Thumbnails
Fast, reliable, and affordable. 200 free thumbnails/month. Multiple formats including AVIF.
Get Free API Key โFrequently Asked Questions
How do I generate a website thumbnail?
Send a GET request to SnapAPI with the target URL and desired dimensions. The API returns a screenshot image you can use as a thumbnail. No server setup or browser installation required.
What size should website thumbnails be?
For most use cases, capture at 1280x800 and display at 640x400 (retina-ready). For smaller grid thumbnails, 400x300 works well. For social sharing cards, use the OG standard of 1200x630.
Can I generate thumbnails in bulk?
Yes. SnapAPI supports unlimited concurrent requests on all plans. Use a concurrency limiter (like p-limit) to process hundreds of URLs in parallel.
How often should I refresh thumbnails?
It depends on your use case. For directories and bookmarks, weekly refreshes are typically sufficient. For monitoring or news sites, daily or even hourly updates may be appropriate.
What's the best image format for thumbnails?
WebP offers the best balance of quality and file size for most applications. AVIF provides even smaller files but is slightly slower to encode. Both are supported by SnapAPI.
Last updated: February 14, 2026