How to Take a Full-Page Screenshot with the ApiFlash API
Capture an entire webpage with ApiFlash: set full_page=true, choose a readiness strategy, save the image, and handle errors, limits, and caching.
To capture a page at its full height with ApiFlash, send a request to https://api.apiflash.com/v1/urltoimage with your access key, a fully qualified target URL, and full_page=true. ApiFlash returns image bytes by default. Its FAQ gives the same direct answer: set the full_page parameter to true. See the ApiFlash API documentation.
1. Make a full-page screenshot with cURL
This saves the response body to a JPEG file. ApiFlash defaults to JPEG, so the extension matches the default format.
curl --get 'https://api.apiflash.com/v1/urltoimage' \
--data-urlencode 'access_key=YOUR_ACCESS_KEY' \
--data-urlencode 'url=https://example.com' \
--data-urlencode 'full_page=true' \
--output screenshot.jpeg
Replace YOUR_ACCESS_KEY with your ApiFlash key and https://example.com with the complete URL you want to capture. Include the URL scheme (https:// or http://). The --get option places the parameters in the query string, and --data-urlencode safely encodes values such as a URL that itself has query parameters.
2. Choose when the page is ready
ApiFlash waits for network_idle by default. A page with ongoing network activity or delayed content may need a different readiness condition. Use the control that reflects how the page actually loads:
| Parameter | Use | Behavior and limits |
|---|---|---|
wait_until |
Choose a page lifecycle condition | Documented values include network_idle (default), dom_loaded, and page_loaded. |
wait_until_timeout |
Bound the wait for the selected condition | Documented range is 1–30 seconds. After the timeout, capture proceeds with what has loaded. |
wait_for |
Wait for a known element to appear | Provide a CSS selector for late content. If no match appears within 15 seconds, capture is aborted. |
scroll_page=true |
Trigger content that loads while scrolling | Scrolls through the page before capture, useful for lazy-loaded elements or scroll-triggered animations. |
delay |
Add a short fixed pause | Accepts 0–10 seconds. Prefer the condition or selector options when possible, since a fixed pause cannot tell whether the needed content is ready. |
For a page whose main content appears after JavaScript inserts a known element, use wait_for. If images load as the visitor scrolls, try scroll_page=true. Use wait_until for a general load state. You can combine suitable readiness options where needed, but avoid adding a long delay without evidence that it helps.
3. Set full-page and output options
full_page=true: captures the full page height. It defaults to false.height: ignored when full-page mode is active. You do not need to set a viewport height to make the capture taller.- Image format: JPEG is the default; PNG and WebP are also documented. Choose the matching output format and filename extension when setting the format.
response_type=json: returns JSON with links to the screenshot and, when requested, extracted HTML or text. Without this option, the response is the image data itself.ttl: controls how long an identical request can use a cached image; documented range is 0–2,592,000 seconds.fresh=true: requests a new capture while leaving the previous cached result in place.
Full-page captures can be large. The API reference lists viewport width and height limits of 16,350 pixels and a viewport-area limit of 33,177,600 pixels. WebP has a maximum output width and height of 16,350 pixels after the scale factor. Very long pages or high-resolution settings can therefore exceed output limits even when the request parameters are otherwise valid. Consult the current reference for supported parameter names and constraints.
4. Python example
Use a query-parameter dictionary rather than assembling the URL by string concatenation; the HTTP library encodes the target URL and parameters.
import requests
response = requests.get(
"https://api.apiflash.com/v1/urltoimage",
params={
"access_key": "YOUR_ACCESS_KEY",
"url": "https://example.com",
"full_page": "true",
"format": "jpeg",
},
timeout=90,
)
response.raise_for_status()
with open("screenshot.jpeg", "wb") as image_file:
image_file.write(response.content)
Keep the key in a server-side secret or environment variable in a deployed application. The example uses a placeholder to keep the request runnable after you provide your own credential.
5. Node.js example
This example uses Node.js with built-in fetch and writes the image bytes to disk.
import { writeFile } from "node:fs/promises";
const params = new URLSearchParams({
access_key: "YOUR_ACCESS_KEY",
url: "https://example.com",
full_page: "true",
format: "jpeg",
});
const response = await fetch(
`https://api.apiflash.com/v1/urltoimage?${params}`,
{ signal: AbortSignal.timeout(90_000) },
);
if (!response.ok) {
const detail = await response.text();
throw new Error(`ApiFlash returned ${response.status}: ${detail}`);
}
const image = new Uint8Array(await response.arrayBuffer());
await writeFile("screenshot.jpeg", image);
For applications that run in older Node.js versions without global fetch or AbortSignal.timeout, use a supported HTTP client and a URL-encoding utility. Avoid logging the full request URL if it contains the access key.
6. GET, POST, and JSON responses
The endpoint accepts GET requests with query parameters and POST requests with form data. GET is convenient for a command-line capture; POST can be useful when your server or HTTP client handles form encoding more naturally. Encode values either way, especially CSS selectors, custom headers, cookies, JavaScript, and URLs with their own query strings.
By default, the response is the raw image, so write the response body as bytes. If you set response_type=json, parse JSON instead and use the returned screenshot link. The JSON mode can also provide links to extracted HTML or text when those are requested. Do not try to save JSON as a JPEG or image bytes as JSON.
7. Keep the access key private
Do not place a live ApiFlash access key in browser JavaScript, a public repository, or a URL exposed in client-side logs. For a browser-facing application, have your server make the ApiFlash request, or use a secured proxy that adds the key on the server side. ApiFlash publishes proxy patterns for Nginx and Cloudflare Workers. Apply your own access controls and request limits to a proxy so it cannot become an unrestricted relay.
8. Troubleshooting
| Symptom or status | Likely cause | What to do |
|---|---|---|
| Only the initial viewport appears | full_page was omitted, misspelled, or false. |
Send full_page=true. The height option does not enable full-page capture. |
| Late text or images are missing | The selected readiness condition completed before that content appeared, or lazy content was never triggered. | Wait for a known CSS selector with wait_for, use an appropriate wait_until, or enable scroll_page=true for scroll-triggered content. |
| Capture fails while waiting for an element | The wait_for selector did not match within the documented 15-second period. |
Check that the selector is valid and present on the target page. If content is conditional, use a different readiness condition instead. |
| Image cannot be opened or has the wrong extension | The request returned an error body or JSON, or the filename extension does not match the requested format. | Check the HTTP status before saving, distinguish response_type=json from raw image output, and use the correct extension for JPEG, PNG, or WebP. |
| HTTP 400 | A required parameter is missing, malformed, or outside a documented range. | Verify the access key and fully qualified URL, encode parameters, and check option limits in the API reference. |
| HTTP 401 or 403 | Credential or authorization problem. | Check that the key is valid and active and that the account is allowed to make the request. Keep it server-side. |
| HTTP 402 | Account or quota payment condition. | Read the response details and check account status and available quota. |
| HTTP 429 | Rate limit exceeded. | Reduce concurrency and retry with exponential backoff. The documented rate is 20 requests per second with a burst of 400; excess processing-rate requests may be delayed, while requests beyond the burst can receive 429. |
| HTTP 500 or transient timeout | Server-side or temporary processing failure. | Retry a limited number of times with exponential backoff and a request timeout. Avoid rapid retries that compound load. |
ApiFlash documents statuses 400, 401, 402, 403, 429, and 500. For 429 responses, its terms of service direct clients to use exponential backoff. Inspect response headers for quota information, or use the quota endpoint described by ApiFlash.
9. Performance, reliability, and cost
- Capture time: full-page images contain more rendered content than viewport captures. Choose a readiness condition that matches the page rather than applying the maximum wait to every request.
- Lazy content: scrolling can trigger more content but can also make a capture take longer. Use it when the page relies on scroll-triggered loading.
- Retries: retry only transient failures such as a temporary server error or rate limit. Use exponential backoff, cap attempts, and avoid retrying malformed requests unchanged.
- Cache: identical parameters may return a cached image. Set
ttlaccording to how often the page changes; usefresh=truewhen you need a new capture without removing the prior cached result. ApiFlash’s FAQ says cached and failed screenshots do not count toward monthly quota. - Quota and rate: inspect response headers or the quota endpoint to monitor usage. The documented processing rate is 20 requests per second, with a burst of 400; design bulk jobs to throttle and handle 429 responses.
- Price: ApiFlash’s homepage lists a free tier of 100 screenshots per month, Lite at $7/month for 1,000, Medium at $35/month for 10,000, and Large at $180/month for 100,000. Pricing can change; verify the current plan page before choosing a plan.
10. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns an image or PDF. Its capture flow accepts cookie and consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and responses identify the page verdict and billing status in headers. Its MCP server lets AI agents using Claude, Cursor, or another MCP client call screenshot tools. The API documentation describes the request options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
ScreenshotNeo also provides Python and Node.js examples and supports full-page capture, viewport and device settings, output formats, readiness controls, and many other options. Its parameter names used by other screenshot APIs also work, which can make switching easier. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000, and every feature is on every plan. Sign up for 1,000 free screenshots a month, with no card.
FAQ
How can I make a full-page screenshot?
Set full_page=true on the ApiFlash URL-to-image request.
Does full-page mode use the height parameter?
No. The documentation says height is ignored when full-page mode is active.
Can I use POST instead of GET?
Yes. ApiFlash accepts GET query parameters and POST form data. Encode values correctly with either method.
Why is the screenshot still missing content below the fold?
Some pages load content only when scrolled. Try scroll_page=true; for a specific late element, wait for its selector.
Does ApiFlash return an image file in every mode?
No. The default response is image bytes, while response_type=json returns JSON containing links.


