Keyword: screenshot api tutorial · Updated May 27, 2026
Screenshot API Quick Start: Your First Screenshot in 60 Seconds
The fastest path from zero to a working website screenshot rendered by an API. Sign up, copy your key, run one curl command, get back a PNG. Then move to Node.js, Python, or PHP, switch to a self-hosted Docker stack on the same endpoint, and let an AI agent call it through MCP — all without leaving this page.
TL;DR — 60 seconds, three commands
- Sign up at dashboard.snapshotflow.com (200 screenshots/month free, no credit card).
- Copy the API key from the dashboard.
- Run the snippet below and open the PNG.
export SNAPSHOTFLOW_KEY=sk_live_xxxxxxxxxxxx curl "https://api.snapshotflow.com/screenshot?url=https://stripe.com&full_page=true" \ -H "X-Api-Key: $SNAPSHOTFLOW_KEY" --output stripe.png open stripe.png
/screenshot endpoint. You skip dependency installs, font setup, Lambda layers, and concurrency tuning — that complexity stays on the vendor's side. See What Is a Screenshot API? for the full architecture diagram.
Prerequisites
You need exactly two things:
- A terminal with
curl(preinstalled on macOS and Linux; available on Windows 10+ via PowerShell). - An email address for the SnapshotFlow free tier — 200 screenshots per month, no credit card.
That's it. No SDK install, no headless Chrome on your machine, no Docker (unless you choose the self-host path in step 5).
Step 1 — Create an account and copy your API key
Open dashboard.snapshotflow.com/#/register and sign up with an email + password (or magic link). Email verification arrives instantly.
Inside the dashboard, open API Keys. A first key is generated automatically — labelled default. Click Copy.
Export the key as a shell variable so you never paste it inline:
export SNAPSHOTFLOW_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
On Windows PowerShell: $env:SNAPSHOTFLOW_KEY="sk_live_...".
.env, GitHub Actions secrets, or your platform's secret manager.
Step 2 — Your first screenshot with curl
The /screenshot endpoint accepts a single required query parameter — url — and returns the raw image bytes. The header X-Api-Key authenticates the request.
curl "https://api.snapshotflow.com/screenshot?url=https://example.com" \ -H "X-Api-Key: $SNAPSHOTFLOW_KEY" \ --output example.png
After roughly a second, example.png lands in your working directory. Open it with your image viewer — you should see example.com rendered exactly as Chromium would draw it on a 1280-wide viewport.
That's the entire happy path. The next sections layer parameters, languages, deployment options, and the agent integration on top of this same 3-line shape.
Step 3 — The five parameters you'll use most
The /screenshot endpoint supports more than 40 parameters (see the API reference). For 90% of use cases you only need these five:
| Parameter | Default | What it does |
|---|---|---|
url | — | Required. Any public URL. Must be URL-encoded if it contains query strings or special characters. |
full_page | false | Capture the entire scroll height, not just the visible viewport. |
width | 1280 | Viewport width in pixels. Use 1440 for desktop hero shots, 375 for iPhone-sized previews. |
format | png | png, jpeg, or webp. WebP is ~30% smaller for the same visual quality. |
wait_for | networkidle | When to consider the page "ready": networkidle, load, domcontentloaded, or a CSS selector like .hero-loaded. |
Combining them is just URL composition:
curl "https://api.snapshotflow.com/screenshot?url=https://stripe.com&full_page=true&width=1440&format=webp&wait_for=networkidle" \ -H "X-Api-Key: $SNAPSHOTFLOW_KEY" \ --output stripe-full.webp
For long-page nuances (lazy images, sticky headers, infinite scroll) read Full Page Screenshot API: How to Capture Long Web Pages Without Cropping or Bugs.
Step 4 — From your language: Node.js, Python, PHP
The API is plain HTTP, so any language with a request library works the same way. Below are the three most common snippets, all calling the identical endpoint.
Node.js / TypeScript
import { writeFile } from "node:fs/promises";
const url = new URL("https://api.snapshotflow.com/screenshot");
url.searchParams.set("url", "https://stripe.com");
url.searchParams.set("full_page", "true");
url.searchParams.set("width", "1440");
const res = await fetch(url, {
headers: { "X-Api-Key": process.env.SNAPSHOTFLOW_KEY! },
});
if (!res.ok) throw new Error(`SnapshotFlow ${res.status}: ${await res.text()}`);
await writeFile("stripe.png", Buffer.from(await res.arrayBuffer()));
Python
import os, requests
res = requests.get(
"https://api.snapshotflow.com/screenshot",
params={
"url": "https://stripe.com",
"full_page": "true",
"width": 1440,
},
headers={"X-Api-Key": os.environ["SNAPSHOTFLOW_KEY"]},
timeout=30,
)
res.raise_for_status()
with open("stripe.png", "wb") as f:
f.write(res.content)
PHP (Guzzle)
<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$res = $client->get('https://api.snapshotflow.com/screenshot', [
'query' => ['url' => 'https://stripe.com', 'full_page' => 'true', 'width' => 1440],
'headers' => ['X-Api-Key' => getenv('SNAPSHOTFLOW_KEY')],
'timeout' => 30,
]);
file_put_contents('stripe.png', $res->getBody());
Ruby, Go, Java, C#, Rust, Elixir — the recipe is the same: GET request, one header, one query string, write the response body as binary. We publish language-specific guides as part of our blog series.
Step 5 — Self-host the same endpoint with Docker Compose
If your team needs data-residency, has offline CI, or is heading past 500k screenshots/month, the hosted plan stops being the cheapest option. SnapshotFlow ships an official Docker Compose stack that exposes the same /screenshot, /batch, /diff, and /jobs endpoints — only the base URL changes.
git clone https://github.com/snapshotflow/snapshotflow-self-host.git cd snapshotflow-self-host cp .env.example .env # set LICENSE_KEY (optional for OSS tier) docker compose up -d # Same API, different host — no key needed in OSS mode: curl "http://localhost:8080/screenshot?url=https://example.com" --output example.png
The compose file boots three containers: fastify-api, browser-pool (Chromium + Puppeteer), and redis. Memory floor is around 1.2 GB; recommended footprint is 4 GB RAM and 2 vCPUs for ~50 concurrent renders.
Step 6 — Let an AI agent call it via MCP
This is where SnapshotFlow diverges from older screenshot APIs. Instead of forcing your LLM agent to learn the HTTP shape, SnapshotFlow exposes the same operations as tools through the Model Context Protocol.
Two surfaces are available out of the box:
- Remote MCP server at
https://api.snapshotflow.com/mcp— point Claude Desktop, Cursor, Goose, or any MCP-aware client at it. - WebMCP via
navigator.modelContext— when the user opens a page that loads our JS shim, the browser-resident agent sees the same tools (screenshot,diff,batch,extract) without an HTTP roundtrip.
Adding the remote server to Claude Desktop is one JSON entry:
{
"mcpServers": {
"snapshotflow": {
"url": "https://api.snapshotflow.com/mcp",
"headers": { "X-Api-Key": "sk_live_xxxxxxxx" }
}
}
}
Once registered, the agent can be asked in natural language — "Take a full-page screenshot of stripe.com at 1440 wide and save it to disk" — and the tool call is routed to the same /screenshot endpoint you used in step 2.
Production checklist
Before you wire the API into a customer-facing flow, walk through the seven items below. They're the smallest delta between a 3-line script and something that won't page you at 2 a.m.
- Store the key as a secret. Never inline it in client-side JS. Browser-callable rendering should use a server-side proxy or our signed URLs.
- Set a sensible timeout. 25–30 s on the client; the API guarantees a response or
504before that. - Cache the response. If the URL + parameters are stable, store the PNG in S3 / R2 / GCS keyed by the request hash. SnapshotFlow also returns an
ETagheader. - Handle
429Too Many Requests. Free tier limits resets monthly; paid plans have per-second concurrency caps. Apply exponential backoff with jitter. - Pin
wait_for. The defaultnetworkidlecovers most pages, but on apps with long-polling or analytics beacons you want a stable CSS selector. - Pick a format intentionally. WebP saves ~30% bytes; JPEG is best for hero images; PNG is best for OG cards where transparency or pixel-precision matters.
- Log the
X-Request-Id. Every response carries one; include it when contacting support so we can trace the render in seconds.
Troubleshooting common errors
| Status | What it means | Fix |
|---|---|---|
401 | Missing or invalid API key. | Re-export SNAPSHOTFLOW_KEY; verify the value matches the dashboard. New keys activate immediately. |
402 | Monthly quota exceeded. | Upgrade in the dashboard or wait for the quota reset. Self-host removes the quota entirely. |
422 | Invalid parameter combination, e.g. format=avif (not yet supported) or width=0. | Check the parameter reference for allowed values. |
504 | Target page didn't reach the wait_for condition in time. | Switch wait_for to load or to a CSS selector that signals readiness. |
| Image is blank | Page has a cookie wall, geo-block, or login form. | Pass headers + cookies parameters, or use country for geo-targeted captures (guide). |
FAQ
How long does it really take to get my first screenshot?
About 60 seconds end-to-end — ~30 seconds to sign up, ~5 seconds to copy the API key, ~3–5 seconds for the first call. Warm-pool calls afterwards return in 150–900 ms.
Do I need a credit card?
No. The free tier ships 200 screenshots/month with no card on file. You only enter billing when you upgrade or exceed quota for a sustained period.
Can I run it on my own server?
Yes. The official Docker Compose stack exposes the same endpoints on localhost. Useful for data-residency, offline CI, and very high volumes.
Which languages have ready-made examples?
This guide ships snippets for curl, Node.js / TypeScript, Python and PHP. Because the API is plain HTTP, any language with an HTTP client works — Ruby, Go, Java, C#, Rust, Elixir, Kotlin, Swift, etc.
How do I let an AI agent take screenshots?
Point your MCP-aware client at https://api.snapshotflow.com/mcp (Claude Desktop, Cursor, Goose, etc.) or use the WebMCP tools registered through navigator.modelContext. The same operations become first-class tools the model can call by name.
Where do I see all the parameters?
The full reference lives in the API docs. Forty-plus parameters are documented, but in practice fewer than ten cover most production needs — the five from step 3 are a good starting set.
Try SnapshotFlow free
200 screenshots per month, MCP-ready, Docker self-host available. No credit card.