Quality Website Screenshot API
Pricing
$10.00 / 1,000 screenshot captureds
Quality Website Screenshot API
Full-page or viewport screenshots (PNG/JPEG/WebP/PDF) from a real headless Chrome browser, with a wait-for-selector option for JS-heavy pages.
Pricing
$10.00 / 1,000 screenshot captureds
Rating
0.0
(0)
Developer
Inn Corp
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Give it URLs, get back full-page or viewport screenshots from a real
headless Chrome browser, not a static-image proxy: PNG, JPEG, WebP, or PDF,
with a waitForSelector option for pages whose real content renders after a
JavaScript call. Every dimension in the output is decoded straight out of
the captured file itself, not estimated beforehand.
Why this exists in a crowded category
"Screenshot API" is a crowded search term on the Apify Store, 1,700+ listed results, and this build does not pretend otherwise. The free market leader pulls real, massive traffic (897 users/30 days, 100,000+ runs/30 days) but sits at a 3.8-star rating; a paid alternative in the same space converts at roughly 63 users/30 days. Read plainly: the demand is proven, the free option's own rating shows real reliability complaints, and most of the 1,700 results are unmaintained hobby projects, not polished products. The bet here is not to win a price war against a free tool. It is to be the one that gets full-page capture right, gives real format choice, and reports honest, decoded-not-guessed metadata about what it actually captured, at a fair price.
What it does
- Launches a real headless Chrome (Playwright) per run and opens a fresh, isolated browser context per URL: no cookies or session state carried between captures.
fullPage(default on) captures the entire scrollable page top to bottom; off captures just the viewport, cut atviewportHeight.- Four output formats: PNG (lossless), JPEG, WebP, and PDF (prints the page as a single page sized to the capture, not paginated like a normal printout).
- Two ways to wait for slow-loading content:
waitForSelector(wait for a specific CSS selector to appear, the reliable choice) ordelayMs(a simple fixed wait, the blunt choice). - The captured file goes to the Actor's default key-value store, the correct Apify pattern for binary output; the dataset record carries a ready-to-fetch URL to it, never a base64 blob bloating the dataset.
- Every
width/heightin the output is decoded from the captured file's own header (PNG IHDR, JPEG SOF, WebP VP8/VP8X/VP8L, PDF MediaBox), not estimated from the page's layout moments before the shot. Real pages reflow between "measure" and "capture" (a lazy image finishes loading, a web font swaps in) often enough that a pre-capture guess is not honest to publish; decoding the actual bytes stored removes the guess entirely.
What it deliberately does not do
- No login or paywall bypass. This Actor renders pages exactly as a normal visitor's browser would: the real default Chrome user agent, no cookie injection, no credential handling. It captures only what is already reachable without an account. If a page shows a login wall to a normal visitor, that is exactly what gets captured, honestly, not something this Actor tries to defeat.
- No bot-detection evasion. Some sites fingerprint headless Chrome and
serve a block page or a challenge instead of real content. This Actor
makes no attempt to spoof past that. If a target site blocks headless
browsers, that shows up in the captured image (or as a
status: "error"record), not as a silently wrong result. - No infinite waits. Navigation uses Chromium's
loadevent, notnetworkidle: real sites keep background connections open forever (analytics beacons, polling, websockets), and waiting for total network silence would turn ordinary pages into guaranteed timeouts. For content that renders after the load event, usewaitForSelector.
Output example
Real records from test runs, local and cloud.
A full-page PNG, from a real cloud run (the assetUrl was fetched back and
independently verified: valid PNG signature, IHDR-decoded dimensions
1280x2590 matching this record exactly, byte-for-byte Content-Length
match):
{"url": "https://en.wikipedia.org/wiki/Web_page","format": "png","fullPage": true,"width": 1280,"height": 2590,"fileSizeBytes": 616121,"assetKey": "screenshot-002-en-wikipedia-org-wiki-web-page.png","assetUrl": "https://api.apify.com/v2/key-value-stores/hK1paxusDVdWktyRR/records/screenshot-002-en-wikipedia-org-wiki-web-page.png?signature=1urIXoaOMUoJMYEhbXNqI","httpStatusCode": 200,"status": "ok","error": null,"capturedAt": "2026-08-25T23:35:17.765Z"}
A malformed URL, caught and charged nothing:
{"url": "not-a-url","format": "png","fullPage": true,"width": null,"height": null,"fileSizeBytes": null,"assetKey": null,"assetUrl": null,"httpStatusCode": null,"status": "error","error": "Only http(s) URLs are supported.","capturedAt": "2026-08-25T23:28:39.347Z"}
Getting the actual image: open assetUrl directly, or fetch it
yourself; it is a plain GET to the key-value store's record endpoint,
https://api.apify.com/v2/key-value-stores/{storeId}/records/{assetKey},
which returns the raw file with the right Content-Type already set. No
separate lookup needed to find the store ID first, assetUrl already has
it baked in.
Input
| Field | Meaning |
|---|---|
urls | Pages to capture. Required. |
fullPage | On (default): entire scrollable page. Off: just the viewport, cut at viewportHeight. |
viewportWidth / viewportHeight | Browser viewport before capture, default 1280x800. |
format | png (default, lossless), jpeg, webp, or pdf. |
waitForSelector | CSS selector to wait for before capturing, for content that renders after a JavaScript call. Optional. |
delayMs | Simple fixed wait before capturing, default 0. Simpler than waitForSelector, blunter: it waits the full amount regardless of whether the page needed it. |
quality | JPEG/WebP compression quality, 1-100, default 90. Ignored for png (always lossless) and pdf. |
pageTimeoutSecs | Wall-clock budget per URL, covering navigation, the wait strategy, and the capture itself. Default 30, 5-120. A page over budget is status: "timeout" and is never charged. |
Status values
ok, error (bad URL, DNS failure, navigation error), or timeout
(pageTimeoutSecs ran out during navigation, the wait strategy, or the
capture itself). Every non-ok record's error field says exactly what
happened. Only ok records are charged.
A page that loads but returns a non-2xx HTTP status (a site's own 404 or
500 page) is still status: "ok" and is charged: the browser rendered
exactly what a visitor would see, and that's the point of a screenshot.
Check the httpStatusCode field if you need to tell these apart from a
normal 200 response.
Typical uses
- Visual regression snapshots for a set of pages, on a schedule.
- Feeding an AI agent a real rendered view of a page instead of raw HTML.
- Archiving how a page looked on a given date (each record's
capturedAtis exact). - Generating a PDF "print view" of a page without opening a browser yourself.
Known limitations, disclosed honestly
- JS-heavy pages may need
waitForSelectortuning. The defaultloadwait covers images, stylesheets, and iframes, but content that renders from a JavaScript call after that point needs an explicit selector (or adelayMs) to exist by the time the shot is taken. This is how the input is designed to be used, not a gap to fix later. - Bot detection can block a headless browser. Some sites specifically fingerprint and block headless Chrome. This Actor does not attempt to spoof past that; a blocked page is captured (or errors) exactly as described above, never silently faked into looking successful.
- Extremely long pages can hit a browser canvas limit. Full-page
capture of a page many tens of thousands of pixels tall can exceed
Chromium's own rendering limits; that surfaces as a
status: "error"record with the underlying reason, not a corrupt file. - PDF is single-page by design.
format: "pdf"renders the capture as one page sized to the content, not a normal multi-page printout: this matches "PDF as an alternative screenshot format," not "print this article for reading."
Fair pricing
Pay per screenshot successfully captured, once pay-per-event pricing is enabled. A URL that errors or times out costs nothing. No subscription.