Website Screenshot API: Screenshot URL to PNG, JPEG or PDF avatar

Website Screenshot API: Screenshot URL to PNG, JPEG or PDF

Pricing

from $0.68 / 1,000 screenshot takens

Go to Apify Store
Website Screenshot API: Screenshot URL to PNG, JPEG or PDF

Website Screenshot API: Screenshot URL to PNG, JPEG or PDF

Website screenshot API: screenshot a URL list to PNG, JPEG or PDF (URL to image), full page up to 4,000 CSS px or exact size, with final URL, HTTP status, title. HTML strings to PDF too: A4/Letter, landscape, margins. Bench 10-10: 17 of 18 checks passed. $0.80 per 1,000; dead links free.

Pricing

from $0.68 / 1,000 screenshot takens

Rating

0.0

(0)

Developer

hiver

hiver

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Website Screenshot API: screenshot any URL to PNG, JPEG or PDF

Paste a list of URLs and get a screenshot of every URL in one run (PNG, JPEG or PDF), or call it as a URL screenshot API from your code. Or send HTML strings (invoices, reports) and get one PDF per item on A4, Letter or Legal paper, portrait or landscape, with your margins: the pdfkit.from_string job without the wkhtmltopdf binary. You get one PNG, JPEG or PDF per page, each with a public link, plus a table with the final URL after redirects, the HTTP status, the page title and the file size. Dead links and error pages show up in the table and cost nothing.

$0.80 per 1,000 screenshots on the free plan ($0.68 on Business). Apify platform usage is included in that price.

Current full-page PNG/JPEG limit: 4,000 CSS pixels. Longer pages are intentionally clipped; each row reports pageHeight and truncatedAt: 4000. Viewport resolution and PDF output are unchanged. The historical measurements below used the older 16,000 px cap, not this safeguard.

Real output from the board test run on 2026-10-11 (build 0.1.15): 4 long pages in, 4 full-page JPEGs and one table with final URL, HTTP status, title, page height and image link

Watch the 2-minute walkthrough (MP4) · Free example on GitHub: weekly screenshots of your pages, changes posted to Slack or Discord

Measured against the alternatives

Our board's Lab bench ran this Actor (build 0.1.10) and three other Store Actors that take a list of URLs on 2026-10-10 11:23 UTC: Apify's own screenshot Actor (apify/screenshot-url), fourwake/screenshot-api and fetch_cat/website-screenshot-generator. Each got the same 9 URLs in three runs: (1) a plain page, an http:// link that redirects to https, the BBC home page with its cookie banner and a small business site; (2) two normal sites and a domain that does not exist; (3) two long Wikipedia articles captured full page (the English "Cat" article, 34,232 px tall with dozens of lazy-loaded photos, and the Chinese "Emoji" article). Each answer was checked against the real pages: page title, final URL, image saved, and for the long pages the real page height and no images still loading.

This Actorapify/screenshot-urlfourwake/screenshot-apifetch_cat/website-screenshot-generator
Runs that succeeded3 of 31 of 2 measured2 of 32 of 3
Fields filled (URL, final URL, HTTP status, title, image link, width, height)100%43% (2 runs)43%67%
Checks passed against the real pages17 of 184 of 11 (2 runs)6 of 1812 of 18
Long pages full page: checks passed7 of 7not measured (see below)1 of 7 (run hit the 5-minute limit)6 of 7
Price per 1,000 screenshots in these runs (dead links free)$0.68no per-screenshot price$3.00$9.17
Run time per run49 s average300 s (hit the limit) and 10 s109 s average17 s average
  • Read it fairly: 9 URLs are a small sample. fetch_cat/website-screenshot-generator is much faster (17 s vs 49 s a run) and filled every field on the long pages too; its run on the list with the dead domain failed. Apify's own Actor did not start on the long-page run because the bench asked it for JPEG, a format it does not offer, so that run is left out of its column (not measured, not a failure of that Actor). The bench also caps every Actor at 1,024 MB, half the 2,048 MB Apify's Actor uses by default, so its time-out on run 1 may come from that cap. Later builds have not been benched again yet.
  • Tested example (Apify run, build 0.1.10, 2026-10-10): the 34,232 px Cat article came back as a 1920x16,000 JPEG (the 16,000 px cap) with text and photos all the way down and imagesPending: 0; the Chinese Emoji article came back full height (4,442 px) with Chinese text and the inline emoji rendered, not empty boxes. We looked at both images.
  • Historical test and reliability caveat (build 0.1.14, 2026-10-10): run lyaywgV4p0bghNCac saved all four full-page images, but recheck hmNdzt27v0kh243rp saved only two of four within 299 seconds. This build uses an explicit 4,000 CSS px safeguard instead of the historical 16,000 px limit. The old recheck did not pass; a new board health verdict is pending.

Common screenshot problems, and the setting that fixes each

ProblemSetting
A full-page screenshot of a long page is blank or has empty boxes below the first screenfullPage: true captures the page screen by screen and waits up to 5 seconds for the images in view. Every row reports pageHeight and imagesPending, so a page that was still loading shows up in the data instead of in your report
You need every image at one exact size, for example 1200x630 for link previewsdevice: custom with viewportWidth and viewportHeight, fullPage off: each image is exactly that size (times deviceScaleFactor)
You only want the top of the page, not the whole scrollfullPage off (the default) captures the first screen only
The screenshot shows a spinner or half-loaded pagewaitUntil: networkidle, waitForSelector with a CSS selector that appears when the page is ready, or delayMs
A cookie banner or chat widget covers the pagehideCookieBanners (on by default), plus your own CSS selectors in hideSelectors
You paid for URLs that did not loadNothing to set: failed URLs and 4xx/5xx error pages are listed with the reason and not charged
You need to know where each URL ended upEvery row has the final URL after redirects, the HTTP status and the page title

HTML to PDF (invoices, reports, wkhtmltopdf and pdfkit jobs)

Put HTML in html instead of (or next to) urls, set format: pdf, and you get one PDF per item, rendered in headless Chromium.

  • html: one HTML string, a list of strings, or {"name": "invoice-1001", "html": "..."} objects (the name goes into the file name and the name column). Up to 2 MiB per item. HTML and URLs can go in the same run.
  • Paper: pageSize A4 (default), Letter, Legal, A3, A5 or Tabloid; landscape: true; margin as one CSS length ("0.5in", "10mm") or an object with top, right, bottom, left; printBackground (on by default).
  • JavaScript runs in a current Chromium, so Promise, fetch and arrow functions work.
  • Empty, non-string or over-2-MiB items come back as rows with the reason and are not charged.
  • Tested example (board run xCcB7tEdn6snKVWj8, build 0.1.19, 2026-10-14): 3 HTML strings and 1 URL (the Wikipedia "Cat" article) in, 4 PDFs out, every page 792 x 612 pt (US Letter landscape), 0 error rows, 4 screenshot-taken charges, 37 s for the run. One of the HTML strings writes its text with Promise and fetch, and that text is in its PDF.
  • Price: the same $0.80 per 1,000 as screenshots (free plan, lower on paid plans), one charge per saved PDF however many pages it has.
wkhtmltopdf / pdfkitThis Actor
pdfkit.from_string(html, ...)html
pdfkit.from_url(url, ...)urls
--page-size LetterpageSize: "Letter"
-O Landscapelandscape: true
--margin-top 0.5in (and right, bottom, left)margin: {"top": "0.5in"}, or margin: "0.5in" for all four sides
--no-backgroundprintBackground: false

Margins default to 0 here, not to wkhtmltopdf's defaults, so set margin if your layout relied on them. Chromium's layout and page breaks will not match wkhtmltopdf byte for byte.

Ready-made input: HTML strings to PDF, Letter landscape.

Calling pdfkit from Python? The free pdfkit-alternative module (MIT) keeps your pdfkit.from_string and pdfkit.from_url calls: change import pdfkit to import pdfkit_compat as pdfkit and each call runs this Actor once with your own Apify token and a charge cap. It maps page-size, orientation, the margin-* options and print-media-type; any other option stops with an error before a run starts.

What you can do with it

  • Thumbnails for directories, link previews, reports and client decks
  • A visual archive of what a list of pages looked like on a given day
  • Checks of how pages render at desktop, laptop, tablet and mobile sizes
  • Before and after a site launch or redesign: run it twice and compare
  • A weekly screenshot of your own pages with a changed / unchanged / failed report in Slack or Discord: free GitHub Actions template (see the FAQ)
  • Broken links in a list: every row says ok, http_error or failed, with the reason
  • HTML or URL to PDF where wkhtmltopdf / pdfkit no longer installs: one PDF per HTML string or URL, A4, Letter or Legal, portrait or landscape, rendered in Chromium (see HTML to PDF above)

Input

Supply urls, html, or both. Inline HTML supports PNG, JPEG and PDF; no wkhtmltopdf binary is needed. For HTML, html accepts a single string, a list of strings, or { "name": "invoice", "html": "<h1>Invoice</h1>" } objects. htmlNames optionally names list entries. Each HTML item gets its own file even when two entries contain the same markup. Names are sanitized and the item position is included to prevent collisions.

{
"html": ["<!doctype html><html><body><h1>Invoice #1001</h1><p>Total: $49.00</p></body></html>"],
"htmlNames": ["invoice-1001"],
"urls": ["https://example.com"],
"format": "pdf",
"pageSize": "Letter",
"landscape": true,
"margin": "0.5in",
"printBackground": true
}

HTML renders on about:blank, with local file/internal browser access blocked and non-HTTP(S) embedded-frame navigations disallowed. Use absolute HTTPS URLs for external CSS, images and scripts; relative URLs have no website base unless you supply an HTTPS <base> tag. JavaScript runs in Chromium; use waitForSelector or delayMs when your application needs extra time. Empty HTML, non-string entries, entries over 2 MiB (UTF-8 bytes), and render failures produce free error rows. Do not put secrets in HTML input.

PDF defaults remain A4, portrait, zero margins, backgrounds on. Paper sizes: A4, Letter, Legal, A3, A5, Tabloid. margin accepts a CSS length (px, pt, in, cm, mm, or zero), or an object with top, right, bottom, left; omitted sides are zero. PDF pagination follows Chromium's print layout. The page options do not change PNG/JPEG output.

FieldWhat it does
urlsOne URL per line. example.com is fine, https:// is added. Duplicates are skipped.
html, htmlNamesInline HTML string/list or named objects, optionally mixed with URLs
formatpng, jpeg or pdf
pageSize, landscape, margin, printBackgroundPDF paper, orientation, margins and backgrounds
fullPageCapture the scrollable page up to 4,000 CSS px; longer pages report truncatedAt: 4000
devicedesktop 1920x1080, laptop 1366x768, tablet 820x1180, mobile 390x844 @2x, or custom width/height
deviceScaleFactor1 to 3, for sharper images
waitUntil, waitForSelector, delayMsWait for load, network idle, a CSS selector, and/or a pause before capture
hideCookieBannersClicks common "accept" buttons and hides known consent pop-ups
hideSelectorsYour own CSS selectors to hide (chat widgets, sticky bars)
darkMode, blockAds, userAgent, timeoutSecs, maxConcurrencyFine control
proxyConfigurationOff by default. Turn on for sites that block data-centre IPs.
{ "urls": ["https://example.com", "https://news.ycombinator.com"], "format": "png", "device": "desktop", "fullPage": false }

Output

One dataset row per URL or HTML item. HTML rows have source: "html", url: null, zero-based htmlIndex, and name; URL rows retain their existing fields. PDF rows add pageSize, landscape, pages (page count); width/height are the first page's actual MediaBox dimensions in points (72 pt/in), not viewport pixels.

{
"url": "https://example.com",
"finalUrl": "https://example.com/",
"status": "ok",
"httpStatus": 200,
"title": "Example Domain",
"imageUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/example.com-327c3fda.png",
"format": "png", "bytes": 79492, "width": 1920, "height": 1080, "seconds": 2.6, "error": null
}

status is ok, http_error (the server answered 4xx/5xx: the error page is still saved, but not charged) or failed (DNS error, timeout, bad URL; error says why). Images are in the run's key-value store, so the links work without logging in.

width and height are the actual PNG/JPEG pixel dimensions, including device scaling. pageHeight is the scrollable page height in CSS pixels before capture; full-page images stop at 4,000 CSS pixels even if the page is longer. imagesPending counts visible <img> elements inside the capture that are still loading after a wait of up to five seconds. Zero means none are pending, not that every image loaded successfully (broken images can be complete). truncatedAt is the CSS pixel cutoff when a full-page image is capped, otherwise null. Full-page PNG/JPEG captures use viewport-sized tiles stitched into one image, without resizing the viewport. Sticky elements keep their document position; fixed overlays are hidden after the first tile to avoid repetition. Raster capture has a total budget of 10 seconds plus 5 seconds per tile (30 seconds for 4 desktop tiles), capped at 90 seconds, and a 10-second budget per tile; both are bounded by the run deadline with five seconds reserved for saving/reporting. Pages are asked for reduced motion; Finite CSS reveal animations are fast-forwarded; infinite CSS animations, JavaScript animation-frame loops and playing videos are paused during tiled raster capture, then restored afterward. Each full-page URL uses a fresh browser to reclaim decoded-image and compositor memory. Navigation waits up to ten additional seconds for main-frame redirects to settle; current-document readiness probes allow up to five seconds for a CPU-busy renderer, within that settlement limit. A document change or destroyed execution context during redirect settlement or preparation/capture retries the complete capture once, never stitches different documents together. When waitUntil: load times out after the current document reached DOMContentLoaded, capture continues and reports loadState: domcontentloaded; explicit networkidle and selector timeouts still fail. loadState records the reached navigation state and navigationRetries counts the one permitted redirect retry. A capture timeout returns a failed, uncharged row rather than a partial image. captureTiles and captureSeconds expose tile count and raster/stitching time; a failed raster still reports elapsed capture time and its timeout stage in error. Full-page raster URLs run serially to bound CPU/memory contention; viewport captures keep maxConcurrency. These fields also appear in the Results dataset view. PDF uses Chromium's print layout on the pageSize paper (A4 by default).

Pricing

Pay per event: you pay per screenshot that loads (HTTP 2xx/3xx). Failed URLs and error pages are free. Apify platform usage is included in the price. Higher Apify plans get a discount automatically:

Event, per 1,000FreeStarter (Bronze)Scale (Silver)Business (Gold)
Screenshot taken (screenshot-taken)$0.80$0.76$0.72$0.68

Worked example: 5,000 screenshots on the Free plan cost 5,000 × $0.0008 = $4.00; on Gold, 5,000 × $0.00068 = $3.40. Dead links and error pages in the list cost nothing.

Known limits

  • Pages behind a login are not supported.
  • Some sites block data-centre IPs or show a bot check; try the proxy option.
  • Cookie-banner removal covers the common consent tools, not every site's custom one; add its selector in hideSelectors.
  • Full-page PNG/JPEG capture stops at 4,000 CSS px tall. Longer pages and endless-scroll feeds are cut there with truncatedAt: 4000. PDF is unaffected.
  • PDF output ignores fullPage and device size; paper size, orientation and margins follow pageSize, landscape, and margin (defaults: A4, portrait, zero). Large documents can have multiple pages but are charged once per saved PDF.
  • Capture only pages you are allowed to capture.

Input example

{
"urls": [
"https://example.com",
"https://news.ycombinator.com",
"https://apify.com"
],
"format": "png",
"fullPage": false,
"device": "desktop",
"hideCookieBanners": true
}

FAQ

How many URLs per run?
As many as you list; runs are bounded by the Actor timeout you set. Start with a few dozen and scale up.

Which pages work?
Public pages that load in a browser without login. Pages behind logins, captchas or bot blocks return an error row and are not charged.

Are cookie banners always removed?
The option hides the common consent banners; unusual ones can remain visible.

Can I get a weekly screenshot of my pages and an alert when one changes?
Yes, with the free website-screenshot-monitor repo (MIT): a GitHub Actions template runs this Actor weekly with your own Apify token, compares each image with the last good capture, and posts a changed / unchanged / failed report to Slack or Discord. Failed URLs stay in the report and never replace a good baseline.

Coming from wkhtmltopdf, pdfkit or imgkit?
wkhtmltopdf's GitHub repo is archived (last push November 2022) and Debian removed its package from testing on 2025-02-05. Debian 13, the base of today's python:3.13-slim image, has no wkhtmltopdf package, so apt-get install wkhtmltopdf finds nothing and pdfkit.from_url() stops at "No wkhtmltopdf executable found" (imgkit: "No wkhtmltoimage executable found"; checked on Debian 13 on 2026-10-12, pdfkit 1.0.0, imgkit 1.2.3). Its engine is a 2012 QtWebKit. The last upstream .deb (0.12.6.1, built for Debian 12) still runs on Debian 13 if you install it by hand, but in the same check it had no Promise, fetch or arrow functions and crashed on 2 of 6 public pages (react.dev and a Wikipedia article: floating point exception and segmentation fault), where headless Chromium printed all 6. This Actor renders in headless Chromium (Playwright) instead: send HTML strings in html (the pdfkit.from_string case) or URLs in urls, with pageSize, landscape and margin in place of --page-size, -O and the --margin-* options (table in HTML to PDF above); png or jpeg gives images (the imgkit case). Ready-made inputs: HTML strings to PDF, Letter landscape and wkhtmltopdf alternative, URL list to PDF.

Is this official?
No. Unofficial and not affiliated with, endorsed by or sponsored by any company or site named in the results or this README.

Something looks wrong or you need a field added?
Open an issue from the Actor's Issues tab with the input and run link.