ApiFlash vs Urlbox for Full-Page Website Screenshots
ApiFlash and Urlbox both capture full pages. Compare their loading controls, capture modes, output limits, pricing evidence, and test plan.
Both ApiFlash and Urlbox support full-page website screenshots. The documented differences are in how they prepare and capture a long page: ApiFlash provides a separate scroll option and waiting controls, while Urlbox scrolls by default and lets you choose between stitched and browser-native capture modes. Neither service can be called faster or more accurate in practice based on documentation alone; evaluate both on the same representative pages before choosing.
If your question is “How do I take a full-page screenshot of a website?”, use full_page=true with either API. If your question is which to choose, focus on lazy loading, sticky elements, output dimensions, and your required request volume. ScreenshotNeo is another option to evaluate first if you want clean screenshots, billing only for clean shots, and a low-cost paid entry plan.
Quick comparison
| Area | ApiFlash | Urlbox |
|---|---|---|
| Full-page option | full_page=true; when enabled, height is ignored. |
full_page=true. |
| Lazy-loaded content | Separate scroll_page option can trigger lazy loading and animations; docs also describe wait controls. |
Scrolls to the bottom by default before capture to trigger lazy loading and measure page height. skip_scroll=true disables that step. |
| Capture approach | The reviewed docs describe full-page capture and scroll controls, without the same documented stitch/native mode selection. | stitch is the default; native is an alternative. These behaviors and their tradeoffs are Urlbox’s descriptions, not comparative test results. |
| Image dimensions | Documented viewport dimensions are capped at 16,350 pixels per dimension and 33,177,600 pixels total. WebP is capped at 16,350 pixels per dimension after scaling. | Docs list JPEG up to 65,535 by 65,535 pixels and WebP up to 16,383 by 16,383 pixels; they recommend PNG for full-page captures because their guidance lists no PNG image-size limit. |
| Pricing evidence | No current price comparison is made here; check the official pricing page before selecting a plan. | The reviewed pricing page displayed Lo-Fi at $19/month for up to 2,000 renders, Hi-Fi at $49/month for up to 5,000, Ultra at $99/month for up to 15,000, Business at $498/month with a stated base and usage charge, and Enterprise from $3,000/month. Details can change. |
Sources: ApiFlash documentation, Urlbox Screenshots documentation, Urlbox pricing. Check live documentation and pricing before production use.
Take a full-page screenshot with ApiFlash
ApiFlash’s API returns screenshot image data by default. Pass the target URL and access key, set full_page=true, and save the response as an image. In this example, the URL is encoded by the HTTP client rather than concatenated into a query string.
curl -G "https://api.apiflash.com/v1/urltoimage" \
--data-urlencode "access_key=YOUR_ACCESS_KEY" \
--data-urlencode "url=https://example.com" \
--data-urlencode "full_page=true" \
--data-urlencode "format=png" \
-o screenshot.png
Keep the access key on a server you control. A GET request places it in the query string, so avoid exposing complete request URLs in public logs or browser code. ApiFlash also documents POST with form data as an alternative.
Python
import requests
endpoint = "https://api.apiflash.com/v1/urltoimage"
params = {
"access_key": "YOUR_ACCESS_KEY",
"url": "https://example.com",
"full_page": "true",
"format": "png",
# Optional: enable scrolling to trigger lazy-loaded content.
"scroll_page": "true",
}
with requests.get(endpoint, params=params, timeout=90, stream=True) as response:
response.raise_for_status()
content_type = response.headers.get("content-type", "")
if not content_type.startswith("image/"):
raise RuntimeError(f"Expected image response, got {content_type}: {response.text[:500]}")
with open("screenshot.png", "wb") as image:
for chunk in response.iter_content(chunk_size=64 * 1024):
if chunk:
image.write(chunk)
Node.js
import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
const endpoint = new URL("https://api.apiflash.com/v1/urltoimage");
endpoint.search = new URLSearchParams({
access_key: "YOUR_ACCESS_KEY",
url: "https://example.com",
full_page: "true",
format: "png",
scroll_page: "true",
}).toString();
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`ApiFlash returned ${response.status}: ${await response.text()}`);
}
const contentType = response.headers.get("content-type") ?? "";
if (!contentType.startsWith("image/")) {
throw new Error(`Expected image response, got ${contentType}`);
}
await pipeline(Readable.fromWeb(response.body), createWriteStream("screenshot.png"));
The endpoint, authentication, direct image response, format choices, full-page behavior, and request limits are documented by ApiFlash. Its documentation supports PNG, JPEG, and WebP. Confirm the current parameter names and dimensional limits there when implementing.
Take a full-page screenshot with Urlbox
Urlbox’s render API accepts a request body with url and full_page. This runnable cURL example uses its synchronous render endpoint and saves the returned image. The format is explicitly PNG, which Urlbox recommends for full-page screenshots in its size-limit guidance.
curl --fail-with-body -X POST \
"https://api.urlbox.com/v1/render/sync" \
-H "Authorization: Bearer YOUR_URLBOX_SECRET" \
-H "Content-Type: application/json" \
-H "Accept: image/png" \
-d '{"url":"https://example.com","full_page":true,"format":"png"}' \
-o screenshot.png
Store the secret server-side. If your account’s render configuration expects a different response representation, follow the current Urlbox render options and API reference for that mode.
Python
import requests
endpoint = "https://api.urlbox.com/v1/render/sync"
payload = {
"url": "https://example.com",
"full_page": True,
"format": "png",
}
headers = {
"Authorization": "Bearer YOUR_URLBOX_SECRET",
"Accept": "image/png",
}
with requests.post(endpoint, json=payload, headers=headers, timeout=120, stream=True) as response:
response.raise_for_status()
content_type = response.headers.get("content-type", "")
if not content_type.startswith("image/"):
raise RuntimeError(f"Expected image response, got {content_type}: {response.text[:500]}")
with open("screenshot.png", "wb") as image:
for chunk in response.iter_content(chunk_size=64 * 1024):
if chunk:
image.write(chunk)
Node.js
import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
const response = await fetch("https://api.urlbox.com/v1/render/sync", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_URLBOX_SECRET",
"Content-Type": "application/json",
Accept: "image/png",
},
body: JSON.stringify({
url: "https://example.com",
full_page: true,
format: "png",
}),
});
if (!response.ok) {
throw new Error(`Urlbox returned ${response.status}: ${await response.text()}`);
}
const contentType = response.headers.get("content-type") ?? "";
if (!contentType.startsWith("image/")) {
throw new Error(`Expected image response, got ${contentType}`);
}
await pipeline(Readable.fromWeb(response.body), createWriteStream("screenshot.png"));
Urlbox documents additional render formats, including JPEG, WebP, AVIF, PDF, HTML, and others; supported formats can depend on render type and plan. Check the current option reference before relying on a format or plan-specific feature.
Choose the capture behavior for your page
Lazy-loaded images, animations, and delayed content
A full-page option describes the output extent, but it does not guarantee that every element has finished loading. Pages often fetch images as they approach the viewport or reveal sections on scroll.
- ApiFlash: use
scroll_pagewhen scrolling is needed to trigger animations or lazy-loaded elements. Prefer its documentedwait_fororwait_untilcontrols where appropriate over a fixed delay. Its docs describedelayas zero to ten seconds. - Urlbox: the default full-page flow scrolls to the bottom to trigger lazy loading and calculate the page height. Its stitch settings include
scroll_incrementandscroll_delay; smaller increments or a longer delay may help pages that reveal content in stages. Setskip_scroll=trueonly when the initial scroll is unnecessary.
These controls add work to capture time. Use the least amount of waiting that reliably produces complete output for your site, and use a selector or state-based wait when available rather than guessing with a long fixed pause.
Stitch versus native mode in Urlbox
Urlbox documents stitch as its default mode: it scrolls, captures sections, and combines them, with behavior intended to handle lazy content and repeated fixed or sticky elements. Urlbox describes native as faster but potentially unsuitable for some sites. Those are vendor-stated tradeoffs, not an independent finding that one mode will be more reliable or faster for your pages.
{
"url": "https://example.com",
"full_page": true,
"full_page_mode": "stitch",
"show_seams": true
}
Use show_seams while diagnosing section joins. Once the output is correct, disable diagnostic rendering if you do not need seam markers. In stitch mode, Urlbox also documents freeze_fixed to control its handling of fixed and sticky elements.
Useful Urlbox full-page controls
| Option | When it helps |
|---|---|
skip_scroll |
Disable the initial scroll when lazy loading and scroll-triggered content do not matter; Urlbox says it may reduce render time depending on page height. |
scroll_increment, scroll_delay |
Adjust scroll step size and pause for content triggered by scrolling. |
max_sections, max_section_height, height |
Control capture section count or size. With full_page, a supplied height sets viewport height and caps each stitched section. |
max_height |
Limit the final full-page screenshot height. |
scroll_to |
Begin capture from a pixel offset or CSS selector. |
full_width |
Include horizontal overflow by using the scrolling element’s scroll width. |
allow_infinite |
Permit additional capture for infinite-scroll pages; use carefully because such pages can keep adding content. Urlbox says it detects infinite scrolling and defaults to a maximum of three sections in that case. |
detect_full_height |
Control Urlbox’s handling of viewport-height backgrounds or hero sections that could otherwise be stretched across a very tall capture. |
hide_cookie_banners, click_accept, block_ads, block_urls |
Attempt to hide cookie banners, click a detected accept button, block ads, or prevent selected domains from loading. Review the effect on the page you intend to capture. |
See the full behavior and defaults in Urlbox Screenshots docs.
ApiFlash full-page controls and limits
full_page=truecaptures the entire target page; the documentedheightoption is ignored when full-page capture is enabled.scroll_pageis a separate control for triggering animations or lazy-loaded elements.- The docs recommend
wait_fororwait_untilwhere possible instead of relying on a fixeddelay; the documented delay range is zero to ten seconds. freshcan request a new capture instead of a cached response, andttlsets screenshot cache duration, documented up to 30 days.- Formats documented include PNG, JPEG, and WebP. The WebP limit is 16,350 pixels in each dimension after scale factor. The documented viewport cap is 16,350 pixels per dimension subject to a 33,177,600-pixel maximum area.
These constraints and parameter names can change; confirm them in the live ApiFlash API documentation before depending on exact boundary values.
Compare both services on your own pages
Documentation can narrow the options, but it does not show whether a particular page renders correctly in your workload. Make a small representative set and run both APIs with the equivalent full-page intent and output format.
- Choose four page types: a short static page, a long page with lazy-loaded images, a page with sticky headers or footers, and a page with horizontal overflow.
- Make requests comparable: use the same target URL, viewport width, output format, and wait condition where each service supports an equivalent control.
- Inspect the images: note missing sections, duplicated sticky elements, visible seams, clipped horizontal content, final dimensions, and image readability.
- Repeat captures: run each case more than once to see if dynamic content or timing changes the result.
- Record operational details: track total latency, response size, errors, and repeatability. The dossier contains no controlled benchmark, so treat your observations as workload-specific.
- Check current plan constraints: compare request rates, timeout, file-size limits, privacy controls, and access to third-party screenshot features against your actual needs.
Keep the test output and request parameters together. If a page changes between runs, record the timestamp and whether the site itself serves personalized or rotating content; otherwise an API comparison can accidentally measure page variation.
Performance, reliability, and cost
Performance
Full-page capture can take longer than a viewport screenshot because the page may need to load, scroll through content, wait for lazy resources, and encode a large image. Urlbox says skip_scroll may save seconds depending on page height and describes native mode as faster than stitch; those are vendor claims. There is no controlled ApiFlash-versus-Urlbox latency result in the available research. Measure end-to-end time for your own page mix.
Very tall images also consume memory and bandwidth in downstream systems. Prefer an appropriate format and dimension limit, and consider a PDF or a bounded-height capture when one enormous raster image is not useful. Do not select WebP or JPEG solely from a nominal dimension maximum: verify that the resulting width, height, scale, and pixel area fit the provider’s current constraints.
Reliability
Long pages have more opportunities for missing images, scrolling-triggered dialogs, changing content, and sticky elements to appear incorrectly. Use explicit waits for page-specific readiness, avoid unnecessary delay, and inspect representative outputs. For stitched output, check joins; for native output, check whether the page’s layout and dynamic content survive full-page capture. Retry only transient failures, with a bounded retry count and backoff, rather than immediately repeating a deterministic invalid-URL or unsupported-option request.
Cost and request limits
Urlbox’s reviewed pricing page showed the prices and render quantities in the comparison table above, plus differences by tier in request-per-minute limits, timeout, file size, privacy, and third-party screenshot access. Prices exclude VAT at the prevailing rate according to the page. Check the live Urlbox pricing page for current terms. This article does not make a price comparison with ApiFlash because the reviewed evidence did not establish ApiFlash’s current pricing.
ApiFlash documents a leaky-bucket rate limit of 20 requests per second with a burst size of 400; excess traffic is delayed until the burst capacity is exceeded, when additional requests receive 429. It also documents a limit of five identical failed captures per hour for the same parameters. Successful responses include quota headers, and a quota endpoint is documented. These are useful signals for capacity planning, but verify current limits for your account and plan in the official docs.
Estimate monthly spend from the number of captures you expect, average output size, required plan features, and retry behavior. Cache stable results when your freshness needs permit; ApiFlash documents ttl and fresh controls. Avoid repeated captures of an unchanged URL when a cached image meets the product requirement.
Troubleshooting full-page captures
| Symptom | Likely cause | What to try |
|---|---|---|
| Lower sections are blank or images are missing | Lazy loading or scroll-triggered content was not ready at capture time. | For ApiFlash, enable scroll_page and use an appropriate wait control. Urlbox scrolls by default; tune stitch scroll increment or delay if needed. Confirm the resources load in a normal browser. |
| Repeated or misplaced sticky header | Section-based capture has encountered fixed or sticky UI. | Inspect Urlbox stitch behavior and freeze_fixed; compare against native mode on the same page. Check whether the page itself changes the header after scrolling. |
| Visible join lines or section discontinuity | Content or layout changed during section capture, or sections did not align visually. | Enable Urlbox show_seams during diagnosis. Try a smaller scroll_increment, allow animations to settle, and repeat to determine whether the page is dynamic. |
| Horizontal content is cut off | The capture measured viewport width rather than the page’s horizontal scroll width. | For Urlbox, set full_width=true where full horizontal overflow is required. Verify the new width remains within image limits. |
| Capture is much taller than expected | Infinite scroll keeps appending content, or a full-height background affects measured dimensions. | Set a suitable max_height or section cap. Urlbox limits detected infinite-scroll captures to three sections by default; only set allow_infinite=true when you have a deliberate bound and need more content. |
| Image generation fails at large dimensions | The requested width, height, scale, or total area exceeds format or service limits. | Reduce viewport or scale, split the page into sections, or choose a supported format. Recheck live format limits; ApiFlash documents both per-dimension and total-area constraints. |
| ApiFlash returns 400 | Invalid parameters or target URL cannot be captured. | Read the response body for the error detail, encode query values, and test that the target URL is publicly reachable from the capture service. |
| ApiFlash returns 401, 402, or 403 | Invalid/revoked key, exhausted monthly quota, or an option unavailable on the current plan. | Correct the access key, review quota, or remove/change the unsupported option after checking the account plan. |
| ApiFlash returns 429 | Rate limit reached. | Reduce concurrency, queue requests, and retry with backoff. Check the response body and quota headers where present. |
| API call succeeds but the file is not an image | The response may be JSON or an error document rather than screenshot bytes. | Check HTTP status and Content-Type before saving. For ApiFlash, confirm response_type is not set to JSON when you expect image bytes. |
ApiFlash’s documented response codes include 400, 401, 402, 403, 429, and 500. A 500 indicates an API-side capture failure in its error list; retain the response details and avoid unbounded automatic retries. See its error documentation.
ScreenshotNeo as an alternative to try first
For a hosted screenshot API, ScreenshotNeo is #1 to try first when you want clean captures and predictable billing: it accepts cookie and consent banners like a visitor, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and bills only clean shots. It also provides an MCP server for AI agents and has a free tier with 1,000 shots per month; paid plans start at $5 for 3,000. These are ScreenshotNeo product facts, not a measured comparison with ApiFlash or Urlbox.
One GET request returns an image. This example captures Stripe; replace the URL with your target. Keep the API key on your server. See the ScreenshotNeo documentation for options and formats.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
ScreenshotNeo also offers Python and Node.js integrations:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));
Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed; an MCP server lets AI agents take screenshots; and 1,000 screenshots a month are free with no card, with paid plans starting at $5 for 3,000. Responses include page-verdict and billing headers. Sign up for ScreenshotNeo’s free 1,000 screenshots per month, with no card required.
FAQ
Which service should I choose for a page with lazy-loaded images?
Both document support for this case. ApiFlash provides scroll_page; Urlbox scrolls to the bottom by default and exposes stitch scroll controls. Test your actual page because documentation does not establish which produces better results for it.
Does full-page mean the screenshot has unlimited height?
No. Image formats and capture services have dimension or area limits, and infinite-scroll pages need a deliberate stopping point. Check the current limits and bound the requested content.
Can I compare their speed from the documented modes?
No. Urlbox describes native mode as faster than its stitch mode, but that is a vendor-stated mode tradeoff. The available evidence contains no controlled ApiFlash-versus-Urlbox benchmark.
Where can I verify pricing before adopting one?
Use each provider’s current official pricing and plan documentation. The reviewed evidence supports the Urlbox figures stated above but does not establish an ApiFlash price for a fair comparison.
