Shotclioos./shot API up · free probe

Screenshot API — POST a URL, get an image back

Website screenshots, one POST away.

Shot renders any public URL to a PNG, JPEG or WebP — full page, a single element, ads blocked. No SDK, no browser to manage. Free 20 renders a day, no credit card.

Quick answer: Shot renders any public URL to a PNG, JPEG or WebP — full page or a single element, ads blocked. Free 20 renders a day, no credit card.

Screenshot of clioos.com rendered live by Shot
Rendered live by Shot — this is a real screenshot of clioos.com, captured with POST /v1/screenshot.
Endpoint
POST /v1/screenshot
One endpoint, Bearer YOUR_KEY, image bytes back.
Formats
PNG · JPEG · WebP
Full page or a single element.
Free quota
20 renders / day
Per key, no credit card. 50 / day per IP.
Cache
1 hour
Cached repeats don’t use quota.

01What Shot does

Six behaviours, each one doing exactly what it says — no SDK, no browser to manage.

01

Full-page capture

Scrolls the page step by step to trigger lazy loading, then captures the whole document — not just the viewport.

02

Element screenshots

Pass a CSS selector and get only that element — a chart, a card, a hero section.

03

Ads blocked

Trackers and ad networks are blocked by default, so captures are clean and faster.

04

Fast, cached

Repeat renders of the same URL are served from a 1-hour cache. Typical render: under 2 seconds.

05

Safe by default

Private IPs, localhost, cloud metadata endpoints and redirect tricks are all blocked. No anonymous endpoint.

06

Simple API

One endpoint, one Bearer YOUR_KEY, image bytes back. JSON metadata mode with Accept: application/json.

02API docs

One endpoint. Synchronous, with image bytes or JSON metadata back.

POSThttps://shot.clioos.com/v1/screenshot30s hard timeout

Examples

cURLsave to shot.png
curl -X POST https://shot.clioos.com/v1/screenshot \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "full_page": true}' \
  --output shot.png
Pythonrequests
import requests

r = requests.post(
    "https://shot.clioos.com/v1/screenshot",
    headers={"Authorization": "Bearer YOUR_KEY"},
    json={"url": "https://example.com", "full_page": True},
    timeout=60,
)
r.raise_for_status()
open("shot.png", "wb").write(r.content)
JavaScriptNode 18+
const res = await fetch("https://shot.clioos.com/v1/screenshot", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ url: "https://example.com", full_page: true }),
});
if (!res.ok) throw new Error(`Shot failed: ${res.status}`);
const { writeFileSync } = await import("node:fs");
writeFileSync("shot.png", Buffer.from(await res.arrayBuffer()));
Gonet/http
package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
)

func main() {
	body, _ := json.Marshal(map[string]any{
		"url": "https://example.com", "full_page": true,
	})
	req, _ := http.NewRequest("POST",
		"https://shot.clioos.com/v1/screenshot", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer YOUR_KEY")
	req.Header.Set("Content-Type", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		panic("Shot failed: " + res.Status)
	}
	f, _ := os.Create("shot.png")
	defer f.Close()
	buf := new(bytes.Buffer)
	buf.ReadFrom(res.Body)
	f.Write(buf.Bytes())
}

Parameters

ParameterDefaultNotes
url—Required. http/https only.
width / height1280 / 800width 320–2000, height 200–4000.
full_pagetrueCapture the whole page.
formatpngpng / jpeg / webp. jpeg & webp take quality 10–100.
device_scale_factor11–2 (retina).
selector—CSS selector: capture only that element.
delay1sExtra wait after load, 0–5s.
block_adstrueBlock ad/tracker requests.
dark_modefalsePrefer dark color scheme.

Responses & errors

Responses carry X-Render-Ms, X-Cache: HIT/MISS and X-RateLimit-Remaining. Errors are JSON.

StatusMeaning
200Image bytes (or JSON metadata with Accept: application/json).
400Bad parameter.
401Bad key.
402Daily limit reached.
422Unsafe URL.
429Rate limited (with Retry-After).
504Render timeout.
502Target unreachable (upstream status included).

Limits

LimitValue
Per key, per minute5 requests
Per key, per day20 renders
Per IP, per day50 renders
Cache1 hour — cached repeats do not consume quota

We do not run JavaScript you send us, and we do not accept custom headers or cookies.

03Pricing

Probe period: free. Every key gets 20 renders/day, no credit card, no expiry while the probe runs. Paid packs are not on sale yet — the probe is measuring what people actually need before we set prices.

If you would pay for a larger pack, tell us below. It only registers interest — no payment, no commitment.

04Get a free API key

05Interested in a paid pack?

Register interest only — no payment is taken, and paid packs do not exist yet.

06Frequently asked questions

How many screenshots can I take for free?

Every free key gets 20 renders per day, plus a 50 renders per day limit per IP. No credit card is required while the probe runs.

What image formats does Shot support?

PNG, JPEG and WebP. JPEG and WebP take a quality setting from 10 to 100. You can capture the full page or a single element with a CSS selector.

Are repeat screenshots cached?

Yes. The same URL and parameters are served from a 1-hour cache, and cached renders do not consume your daily quota.

Is there a rate limit?

Yes: 5 requests per minute per key, 20 renders per day per key, and 50 renders per day per IP. Over the limit you get a 429 or 402 response with a Retry-After header.

Can Shot screenshot private or internal URLs?

No. Private IPs, localhost, cloud metadata endpoints and redirect tricks are blocked. Only public http/https URLs are rendered.

07Privacy & data retention

Your email is used only to send your verification code and API key, and to tell you when paid packs launch. It is never sold or shared.

Render logs (the URL you asked for, when, and whether it succeeded) are kept for quota enforcement and statistics while the probe runs. Cached screenshots expire after 1 hour. Expired unused verification codes are deleted automatically.

To delete your account, API key and render history, email contact@clioos.com from the same address and we will remove them.