Free Screenshot URL (No API Key)
A keyless screenshot endpoint — GET /api/v1/public/screenshot?url=... returns a PNG, JPEG, or WebP image with no API key and no signup. Rate limits, parameters, caps, and embed examples.
You can capture a website screenshot from ScreenshotAPI without an API key and without signing up. Request this URL and you get image bytes back:
https://screenshotapi.to/api/v1/public/screenshot?url=https://example.comThat is a complete, working request. It responds with Content-Type: image/png and the raw image, so it can be dropped straight into an <img src>, a Markdown image, or any HTTP client. Access-Control-Allow-Origin is *, so it also works from browser JavaScript.
This is the keyless tier. It is rate limited to 8 requests per minute per IP, capped at 1920×2000, and does not support PDF output. It is built for demos, prototypes, personal projects, and low-volume embeds. For production workloads, create a free API key — that raises you to 200 screenshots per month at no cost and unlocks the full Screenshot API (PDF, 10000px height, stealth mode, custom wait strategies, caching, webhooks).
Endpoint
GET /api/v1/public/screenshot
POST /api/v1/public/html-to-image
GET /api/v1/public/metadataNo authentication header. No account. These are the same endpoints that power the browser-based free tools.
Quick start
<img
src="https://screenshotapi.to/api/v1/public/screenshot?url=https://example.com&width=1280&height=800"
alt="Screenshot of example.com"
width="1280"
height="800"
/>curl "https://screenshotapi.to/api/v1/public/screenshot?url=https%3A%2F%2Fexample.com&width=1280&height=800&format=png" \
--output screenshot.pngconst params = new URLSearchParams({
url: 'https://example.com',
width: '1280',
height: '800',
format: 'webp'
})
const res = await fetch(
`https://screenshotapi.to/api/v1/public/screenshot?${params}`
)
if (res.status === 429) {
// The keyless tier is rate limited. The body tells you where to get a key.
const { message, signupUrl } = await res.json()
throw new Error(`${message} (${signupUrl})`)
}
const blob = await res.blob()Always URL-encode the url value when you build the request programmatically. In hand-written HTML a plain https://example.com works because the browser encodes it, but an unencoded target that itself contains & or ? will be truncated.
Query parameters
GET /api/v1/public/screenshot
Required
| Parameter | Type | Description |
|---|---|---|
url | string | The page to capture. https:// is added if you omit the scheme. Private, reserved, and cloud-metadata addresses are rejected. |
Optional
| Parameter | Type | Default | Description |
|---|---|---|---|
format | string | png | png, jpeg, or webp. pdf is not available on the keyless tier. JPEG and WebP are encoded at quality 85. |
fullPage | string | false | true captures the entire scrolling page instead of the viewport. |
width | number | — | Viewport width in pixels. Maximum 1920. |
height | number | — | Viewport height in pixels. Maximum 2000 (the authenticated API allows 10000). |
deviceScaleFactor | number | — | Pixel density multiplier, for Retina-quality output. |
device | string | — | A device preset that sets width, height, and pixel density together. See below. Overrides width, height, and deviceScaleFactor. |
darkMode | string | false | true sends a prefers-color-scheme: dark hint before capturing. |
blockAds | string | false | true hides ad slots and trackers. |
removeCookieBanners | string | false | true dismisses consent and cookie overlays. |
removePopups | string | false | true closes newsletter and interstitial popups. |
mockup | string | — | Frame the capture in a device mockup: browser, iphone, or macbook. |
Boolean parameters are strings in the query: fullPage=true, not fullPage=1.
Device presets
device | Viewport | Pixel density |
|---|---|---|
desktop | 1280×800 | 1× |
desktop-hd | 1920×1080 | 1× |
ipad | 820×1180 | 2× |
ipad-pro | 1024×1366 | 2× |
iphone-15-pro | 393×852 | 3× |
iphone-se | 375×667 | 2× |
pixel-8 | 412×915 | 3× |
galaxy-s23 | 360×780 | 3× |
curl "https://screenshotapi.to/api/v1/public/screenshot?url=https%3A%2F%2Fexample.com&device=iphone-15-pro&darkMode=true" \
--output mobile-dark.pngHTML to image
POST /api/v1/public/html-to-image renders a raw HTML string instead of navigating to a URL. Send JSON:
curl -X POST "https://screenshotapi.to/api/v1/public/html-to-image" \
-H "Content-Type: application/json" \
-d '{"html":"<h1 style=\"font-family:system-ui\">Hello</h1>","width":1200,"height":630,"format":"png"}' \
--output card.png| Field | Type | Notes |
|---|---|---|
html | string | Required. Maximum 100,000 characters. |
format | string | png, jpeg, or webp. |
fullPage | boolean | JSON boolean here, not a string. |
width | number | Maximum 1920. |
height | number | Maximum 2000. |
Custom CSS and JavaScript injection are not available on the keyless tier. Inline styles inside your html work normally.
URL metadata
GET /api/v1/public/metadata?url=... returns the page's title, description, and Open Graph / Twitter card tags as JSON — useful for building link previews alongside the image. It is rate limited separately at 20 requests per minute per IP.
curl "https://screenshotapi.to/api/v1/public/metadata?url=https%3A%2F%2Fexample.com"Limits
| Limit | Keyless tier | Free API key |
|---|---|---|
| Authentication | None | x-api-key |
| Rate limit | 8 requests/minute per IP | 200 screenshots/month |
| Max width | 1920 | 1920 |
| Max height | 2000 | 10000 |
| Formats | PNG, JPEG, WebP | PNG, JPEG, WebP, PDF |
| Full page | Yes | Yes |
| Custom JS / CSS injection | No | Yes |
| Stealth mode, wait strategies, response caching, webhooks | No | Yes |
| Usage dashboard and logs | No | Yes |
The keyless rate limit is a best-effort, per-instance speed bump — not a quota you can rely on. It resets unpredictably and may tighten at any time without notice, and requests are queued behind a small shared concurrency pool. Do not build a production feature on it. A free API key gives you a stable monthly allowance, your own concurrency, and usage visibility, and never changes underneath you.
Responses
A successful request returns the image bytes with Content-Type: image/png, image/jpeg, or image/webp.
Every response also carries:
| Header | Meaning |
|---|---|
x-ratelimit-limit | Requests allowed in the current window. |
x-ratelimit-remaining | Requests left in the current window. |
x-screenshotapi-docs | A link back to this page. |
x-cache | HIT if served from the short-lived render cache, MISS if freshly rendered. |
x-duration-ms | Server-side render time. |
Errors
Error responses are JSON and include a docsUrl, plus a signupUrl when an API key would lift the limit you hit.
| Status | Meaning |
|---|---|
400 | Invalid options (unsupported format, size over the cap) or a blocked target (private, reserved, or metadata address). |
429 | Keyless rate limit reached. Includes retryAfterSeconds and signupUrl. |
502 | The page could not be captured — unreachable, or the site blocks automated browsers. |
503 | The shared keyless render pool is saturated. Retry shortly, or use an API key. |
{
"error": "Rate limit reached",
"message": "Too many requests. Try again in 41s. This is the keyless free tier — a free API key raises the limit to 200 screenshots/month with no card: https://screenshotapi.to/sign-up",
"retryAfterSeconds": 41,
"rateLimited": true,
"signupUrl": "https://screenshotapi.to/sign-up",
"docsUrl": "https://screenshotapi.to/docs/api/free-screenshot-url"
}Caching and embedding
Successful image responses are sent with Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600, and identical requests within a short window are served from a render cache (x-cache: HIT).
If you embed the URL in a page that gets real traffic, cache or store the image on your side rather than re-requesting it on every page view. A screenshot of a given URL rarely changes minute to minute, and re-rendering it on every visit will run you into the rate limit. For a durable version of this pattern — capture once, store the result, serve it from your own CDN — use an API key and the caching options on the authenticated endpoint.
Measured behaviour
Captured against production on 2026-07-26 by requesting https://example.com at 1280×800:
| Request | Result |
|---|---|
| Cold render, PNG 1280×800 | HTTP 200, image/png, 19,655 bytes, 1,205 ms server-side |
| Same request, cached | HTTP 200, x-cache: HIT, 103 ms end-to-end |
| Full page, WebP | HTTP 200, image/webp, 1,149 ms server-side |
device=iphone-15-pro&darkMode=true | HTTP 200, PNG 1179×2556 (3× density) |
format=pdf | HTTP 400 — Format must be png, jpeg, or webp. |
width=4000 | HTTP 400 — width must be between 1 and 1920. |
| 9th request in one minute | HTTP 429 with retryAfterSeconds and signupUrl |
Render time depends on the target page; a heavy, script-driven site takes longer than a static one.
When to move to an API key
Get a free API key — 200 screenshots a month, no credit card — as soon as any of these is true:
- You need more than 8 captures a minute, or predictable throughput.
- You need PDF output, or a page taller than 2000 pixels.
- You need custom JavaScript or CSS injection, stealth mode, or a specific wait strategy.
- You need to see your usage, or be able to debug a failed capture.
- The screenshot is part of something you ship to users.
Everything on this page maps one-to-one onto the authenticated endpoint. format becomes type, darkMode=true becomes colorScheme=dark, and device presets become explicit width / height / devicePixelRatio values. See the Screenshot API reference for the full parameter set and the authentication guide for how to send your key.
Acceptable use
The keyless endpoints capture public web pages only. Requests to localhost, private networks, reserved ranges, and cloud metadata endpoints are rejected. Do not use them to bypass paywalls, authentication, consent screens, or access controls, and do not run unbounded automated loops against them. See the terms.