Directories of tools and startups, bookmark managers, link-in-bio pages, agency portfolios, admin panels listing customer sites, and search results all look better with a picture of each website. A thumbnail API turns a URL into that picture, so you don't have to run a browser fleet to keep thousands of them current.
A clean desktop thumbnail
Render at a normal desktop size so the site shows its real layout, then scale it down. Blocking cookie banners, ads and chat widgets matters more for thumbnails than anywhere else: at 400 px wide, a consent dialog is all you'd see.
curl -X POST "https://shotkit.net/api/take" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","viewport_width":1280,"viewport_height":800,"image_width":400,"format":"webp","image_quality":80,"block_cookie_banners":true,"block_ads":true,"block_chats":true,"reduce_motion":true}' \
--fail-with-body -o shot.webpreduce_motion finishes CSS animations, so hero sections aren't caught halfway through fading in.
Embed the URL directly
A GET URL with your access key returns the image, so it can be the src of an <img>. Sign the URL so its parameters can't be changed, and turn on caching:
<img
src="https://shotkit.net/api/take?access_key=…&url=https%3A%2F%2Fexample.com&viewport_width=1280&viewport_height=800&image_width=400&format=webp&block_cookie_banners=true&cache=true&cache_ttl=604800&signature=…"
width="400" height="250" loading="lazy" alt="example.com" />The first view renders the thumbnail; every later view is redirected to the cached file on the CDN and is free. For a directory, render ahead of time with response_type=empty when a site is added, so visitors never wait.
Keep thumbnails fresh
cache_ttlsets how long a thumbnail is reused, from 4 hours to 30 days.- Add a
cache_keylike the current week (2026-W44) to refresh every thumbnail on a schedule, whatever the TTL. - Send
Cache-Control: no-cacheto re-render one site on demand, for example when its owner asks.
Handle sites that fail
Some URLs are down, parked or blocked. By default a 4xx or 5xx from the site fails the request with host_returned_error instead of returning a picture of an error page, and failed requests don't count toward your quota. Show a placeholder in your UI when the image fails to load. To also catch parked domains and soft errors, fail on their text:
curl -X POST "https://shotkit.net/api/take" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","viewport_width":1280,"viewport_height":800,"image_width":400,"format":"webp","fail_if_content_contains":["domain is for sale","This site can'\''t be reached"]}' \
--fail-with-body -o shot.webpFrequently asked questions
What size should website thumbnails be?
Render at a desktop viewport (1280 × 800 is a good default) and scale down with image_width to the size you display, doubled for retina screens: image_width: 800 for a 400 px card.
Do repeat views count toward my monthly screenshots?
No. With cache=true, only the first render of a URL counts. Every request after that is a free cache hit until it expires.
Can I show a mobile thumbnail instead?
Yes. Set viewport_device to a phone such as iphone_15_pro, which sets the size, pixel ratio and mobile user agent.
What about sites that block bots?
Most sites render normally. Some with aggressive bot protection may show a challenge page; a custom user_agent or your own proxy helps with some of them, and fail_if_content_contains keeps challenge pages out of your thumbnails.