Website Screenshot API: Full-Page PNG, JPEG & PDF
Pricing
from $0.61 / 1,000 screenshots
Website Screenshot API: Full-Page PNG, JPEG & PDF
Screenshot web pages from a list of URLs as PNG, JPEG or PDF. Use when you need an image of a public page. Input: urls, optional format, fullPage, device, darkMode. Output per URL: screenshot file URL, final URL, HTTP status, title, size. Cookie banners hidden; failed pages not charged.
Pricing
from $0.61 / 1,000 screenshots
Rating
0.0
(0)
Developer
Phaux
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
A website screenshot tool you can call from the Console, the API or a schedule: capture full page screenshots, viewport shots or URL to PDF files for a list of public web pages, and get a direct download link for each one.
Take screenshots of any public web page as PNG, JPEG or PDF: the full scrolling page, only the viewport, one element or a pixel region, on desktop or an emulated phone or tablet, in light or dark mode. Cookie banners are hidden and lazy-loaded images are loaded before capture. Each file is saved to the run's key-value store, and its direct download URL is returned in the dataset.
You pay only for successful screenshots. Errors, timeouts, blocked pages and error pages (HTTP 4xx/5xx) are never charged.
Quick start for AI agents and API users
- What it does: Screenshot web pages from a list of URLs as PNG, JPEG or PDF.
- When to use it: When you need an image of a public page.
- Example input (the form's prefill; it finishes in under a minute):
{"urls": ["https://apify.com","https://en.wikipedia.org/wiki/Web_scraping"]}
- Example output: one real dataset row from run
luDLGZY6UnHexrjFC(2026-10-23), with long fields shortened and empty fields left out. Fields not shown are listed in the output table below.
{"url": "https://en.wikipedia.org/wiki/Web_scraping","finalUrl": "https://en.wikipedia.org/wiki/Web_scraping","httpStatus": 200,"title": "Web scraping - Wikipedia","screenshotUrl": "https://api.apify.com/v2/key-value-stores/bn8uBJ9vFUhDiGolu/records/0001-en-wikipedia-org-wiki-Web-scraping-0dbff88b.png?signature=3m9Hvb...","key": "0001-en-wikipedia-org-wiki-Web-scraping-0dbff88b.png","format": "png","contentType": "image/png","bytes": 2362697,"fullPage": true,"viewport": {"width": 1280,"height": 800},"pageHeight": 10474,"darkMode": false,"cookieBannersHidden": 0,"stickyElementsAdjusted": 4,"adRequestsBlocked": 0}
- Cost (pay per event, Free-plan prices): Screenshot $0.00089. Failed items are not charged.
- From an AI agent: with the Apify MCP server, call
call-actorwith actorphaux/website-screenshots, or load it as its own tool withhttps://mcp.apify.com?tools=phaux/website-screenshots. Read results withget-dataset-items.
What does Website Screenshots do?
- Opens each URL in headless Chromium, waits for the page to settle, and captures it.
- Formats:
png,jpeg(withjpegQuality) andpdf(paper size, landscape and background options). - Full page or viewport, an element (
elementSelector) or a region (clip). Full-page captures are cropped at 10,000 px by default (maxHeight; raise it up to the 20,000 px hard cap).truncatedAtPxin the output tells you when a page was cut. - Device emulation: iPhone 15 Pro / Pro Max, iPhone 14, Pixel 7 / 5, Galaxy S9+, iPad Pro 11, iPad Mini, Galaxy Tab S9, and desktop Chrome or Safari profiles. Each sets the viewport, pixel ratio, touch support and user agent.
- Dark mode, retina output (
deviceScaleFactor2 or 3), hiding your own selectors, and ad-network blocking.
Why use it?
| Common screenshot problem | What this Actor does |
|---|---|
| Failed captures still cost credits | You're charged only when an image or PDF is actually saved. Failures go to FAILED_URLS with a reason, free of charge. |
| Half-loaded pages and spinners | It waits for load, then up to 3 s for network idle, then web fonts, then your waitForSelector, then delayMs. |
| Missing lazy-loaded images | It scrolls the page quickly (capped by maxScrollMs) and scrolls back to the top before capturing. |
| Sticky headers repeated or covering content | Fixed and sticky elements are shown once at the top by default, or hidden (stickyElements). |
| Need only part of the page | Use maxHeight, fullPage: false, elementSelector or clip. |
| Emoji render as boxes | Colour-emoji and CJK fonts are installed. |
| Hung runs | Each page has a 60 s limit by default. If a full-page capture takes over 30 s, the top 4,000 px are captured instead (captureFallback: true), so you still get a result. The browser restarts after a crash. |
Use cases: website monitoring and visual archives, SEO and ad audits, link previews and thumbnails, compliance evidence, and saving pages as PDF.
How to use it
- Add one or more page URLs to
urls. - Pick a
formatand, if needed,fullPage,deviceordarkMode. - Run the Actor. Open the Overview dataset view to see each
screenshotUrl, or download all files from the key-value store. - To call it from code, use the Apify API or the MCP server (see below).
- To detect visual changes between runs, turn on
visualDiff(see the tutorial below).
Tutorial: visual regression testing and change monitoring with visual diff
Turn on Visual diff (visualDiff: true) and each new screenshot is compared with a baseline. The result tells you what percentage of the page changed, where it changed (a bounding box), and gives a diff image with the changed pixels in red. It's off by default, and turning it on costs nothing extra: you still pay per screenshot as usual.
Where the baseline comes from:
- Previous run (default): the last screenshot of the same URL with the same settings is kept in a named key-value store in your Apify account (
baselineStoreName, defaultwebsite-screenshots-baselines). The first run only saves baselines (status: "no_baseline"), and every later run compares with the one before. - An image you choose: put public PNG/JPEG links in
baselineImageUrls, in the same order asurls. For example, use ascreenshotUrlfrom an earlier run, or an approved design export. SetupdateBaseline: falseto keep comparing with a fixed reference.
Worked example: watching a fast-changing page (real runs, 22 Oct 2026). We used the Hacker News front page, viewport only:
{"urls": ["https://news.ycombinator.com/"],"fullPage": false,"visualDiff": true,"baselineStoreName": "vd-tutorial-hn"}
- 11:03 PM ET, first run (
nmogl5moJDVeY3NjN):"status": "no_baseline","baselineUpdated": true. The screenshot is saved as the baseline and there is nothing to compare yet. - 11:13 PM ET, same input (
X5YAcj9MRublfZZ2t, 6 s): compared with the 11:03 PM baseline:
"visualDiff": {"status": "compared","baselineSource": "store","baselineTakenAt": "2026-10-23T03:03:56.232176Z","percentChanged": 3.57,"changedPixels": 36553,"totalPixels": 1024000,"changedArea": {"x": 135, "y": 47, "width": 535, "height": 738},"newSize": {"width": 1280, "height": 800},"baselineSize": {"width": 1280, "height": 800},"sizeChanged": false,"pixelTolerance": 32,"diffImageUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/0000-news-ycombinator-com-f1f3bd09-diff.png","baselineUpdated": true}
In ten minutes, 3.57 % of the pixels changed. The diff image showed exactly what you would expect: several stories swapped places, and points, comment counts and "hours ago" values were updated. The header, the layout and the stories that stayed put came out faded grey with no red.
- Same page, fixed baseline (
0PSff9Z2k8reaU8R0): we passed the first run'sscreenshotUrlinbaselineImageUrlswithupdateBaseline: false. It returned"baselineSource": "url"and"percentChanged": 3.268. This is how you compare against an approved reference image.
Turn it into a monitor. Create a Schedule (for example hourly or daily) with visualDiff: true. Then filter the dataset on visualDiff.percentChanged, or open the Visual diff dataset view to see the screenshot and the diff image side by side. You can also use an Apify integration (webhook, Slack, email, Zapier/Make) to act when percentChanged is above your threshold, for example 1 % for a landing page or 0.1 % for a pricing table.
Tips for fewer false alarms:
- Hide parts that always change (ads, carousels, clocks, "x minutes ago", cookie bars) with
hideSelectors, or capture just one part withelementSelectororclip. - Keep the same
device, viewport,fullPageanddarkModebetween runs. The stored baseline is per URL and per settings, so a change in settings starts a new baseline instead of giving a false 100 %. diffPixelTolerance(default 32 of 255) ignores anti-aliasing and JPEG noise. Use 0 to count every pixel.- If the page got taller or shorter, the extra area counts as changed and
sizeChangedistrue. - PDF output can't be diffed. Use
pngorjpeg. - A diff problem (for example an unreachable baseline URL) is reported in
visualDiff.error. It never fails the screenshot itself. - Baseline images are stored in your own account (one image per URL and settings), so they count toward your Apify storage like any named store.
Input
{"urls": ["https://apify.com", "https://en.wikipedia.org/wiki/Web_scraping"],"format": "png","fullPage": true,"viewportWidth": 1280,"viewportHeight": 800,"device": "","darkMode": false,"hideCookieBanners": true,"waitForSelector": "","delayMs": 500}
Only urls is required; every other option has a working default.
| Field | Type | Default | Description |
|---|---|---|---|
urls | array | required | Public web pages to capture (http/https). Duplicates are removed. No login or credentials are supported. |
format | string | "png" | Image (PNG/JPEG) or a PDF of the page. Allowed: png, jpeg, pdf. |
fullPage | boolean | true | Capture the whole scrollable page. Off = only the visible viewport. |
maxHeight | integer | 10000 | Crop full-page captures to this height from the top, in pixels. Default 10,000 px; raise it up to 20,000 px (hard cap). 0 = up to the 20,000 px cap. When a page is cut, truncatedAtPx in the output says where. |
viewportWidth | integer | 1280 | Browser window width in CSS pixels (ignored when a device is chosen). |
viewportHeight | integer | 800 | Browser window height; this is the image height when Full page is off. |
deviceScaleFactor | string | "1" | Device pixel ratio (ignored when a device is chosen). Allowed: 1, 2, 3. |
device | string | "" | Emulate a phone/tablet: its viewport, pixel ratio, touch and user agent. Allowed: iPhone 15 Pro, iPhone 15 Pro Max, iPhone 14, Pixel 7, Pixel 5, Galaxy S9+, iPad Pro 11, iPad Mini, Galaxy Tab S9, Desktop Chrome, Desktop Chrome HiDPI, Desktop Safari. |
darkMode | boolean | false | Ask the page for its dark colour scheme (prefers-color-scheme: dark). |
hideCookieBanners | boolean | true | Hide common consent pop-ups (OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics, Sourcepoint and generic cookie bars). Nothing is clicked or accepted. |
blockAds | boolean | true | Block requests to common ad/tracking networks for cleaner, faster captures. |
waitUntil | string | "load" | Navigation event to wait for before the steps below. Allowed: load, domcontentloaded, networkidle. |
waitForNetworkIdleMs | integer | 3000 | Wait up to this long for network requests to settle (prevents half-loaded screenshots). It never fails the capture. |
waitForSelector | string | — | CSS selector that must be visible before capturing, e.g. '#main' or '.product-grid'. |
waitForSelectorTimeoutSecs | integer | 10 | Fail (not charged) if the selector does not appear in time. |
delayMs | integer | 500 | Fixed delay right before the capture, for animations. |
scrollToLoadLazyContent | boolean | true | For full-page captures, scroll down quickly (time-capped) to trigger lazy loading, then scroll back to the top. |
maxScrollMs | integer | 4000 | Hard cap on scrolling time so long/infinite pages stay fast. |
stickyElements | string | "unstick" | How fixed/sticky headers and widgets are handled in full-page captures. Allowed: unstick, hide, keep. |
hideSelectors | array | — | CSS selectors to hide before capturing (chat widgets, banners, ...). |
elementSelector | string | — | CSS selector; capture only the first matching element. |
clip | object | — | Region in page pixels: {"x":0,"y":0,"width":1280,"height":600}. |
jpegQuality | integer | 80 | JPEG compression quality from 1 (smallest file) to 100 (best quality). Used only when format is jpeg. |
pdfFormat | string | "A4" | Paper size of the PDF. Used only when format is pdf. Allowed: A4, Letter, Legal, A3, Tabloid. |
pdfLandscape | boolean | false | Print the PDF in landscape orientation. Used only when format is pdf. |
pdfPrintBackground | boolean | true | Include background colours/images in PDFs. |
visualDiff | boolean | false | Compare each PNG/JPEG screenshot with a baseline and add visualDiff (percentChanged, changedArea, diffImageUrl). Off by default; no extra charge. |
baselineStoreName | string | "website-screenshots-baselines" | Named key-value store in your account that keeps the last screenshot per URL and settings. |
baselineImageUrls | array | — | Optional baseline image links, in the same order as urls; they take priority over the stored baseline. |
updateBaseline | boolean | true | Save each new screenshot as the next baseline. Off = keep a fixed reference. |
diffPixelTolerance | integer | 32 | Per-channel colour difference (0–255) above which a pixel counts as changed. |
failOnHttpError | boolean | true | On: error pages are not captured and not charged. Off: capture them anyway. |
navigationTimeoutSecs | integer | 30 | How long to wait for the page to load on each attempt, in seconds. Slow pages that exceed it are retried (maxRetries) and then reported in FAILED_URLS, not charged. |
maxRetries | integer | 1 | Retries for timeouts and browser errors. |
maxConcurrency | integer | — | Pages captured at the same time. Default: 2 per GB of memory (2 at the default 1 GB), up to 8. |
proxyConfiguration | object | {"useApifyProxy": false} | Usually not needed. Use a proxy only for geo-specific views. Datacenter Apify Proxy or your own proxy URLs only; residential proxy isn't supported. |
captureTimeoutSecs | integer | — | Time allowed for rendering/encoding the image itself. Default 30 s. If a full-page capture times out, it is retried once cropped to the top 4,000 px (captureFallback: true in the output). |
maxLoadWaitMs | integer | 10000 | With waitUntil=load: after the DOM is ready, wait at most this long for the load event (slow third-party assets no longer stall the run). |
detectBlockedPages | boolean | true | Treat bot walls ('Access denied', 'Just a moment...', 'Unknown Error') and blank renders as failures, so you are not charged for them. |
pageTimeoutSecs | integer | — | Total time budget per URL attempt, default 60 s; pages that keep the browser busy longer are abandoned (not charged). |
Output example
One dataset item per successful screenshot:
{"url": "https://apify.com","finalUrl": "https://apify.com/","httpStatus": 200,"title": "Apify: Full-stack web scraping and data extraction platform","screenshotUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/0000-apify-com-7c0cb881.png","key": "0000-apify-com-7c0cb881.png","format": "png","contentType": "image/png","bytes": 977392,"fullPage": true,"device": null,"viewport": {"width": 1280, "height": 800},"pageHeight": 10036,"darkMode": false,"cookieBannersHidden": 5,"stickyElementsAdjusted": 17,"adRequestsBlocked": 17,"loginFormDetected": false,"durationMs": 11934,"timingsMs": {"domReady": 800, "load": 700, "networkIdle": 1300, "capture": 650},"truncatedAtPx": null,"takenAt": "2026-10-20T11:20:00Z"}
Output fields
| Field | Type | Description |
|---|---|---|
url | string | The URL you submitted. |
finalUrl | string or null | URL after redirects. |
httpStatus | number or null | HTTP status of the page. |
title | string or null | Page title. |
screenshotUrl | string | Direct URL of the saved screenshot in the run's key-value store. |
key | string | Key-value store record key of the screenshot. |
format | string | png, jpeg or pdf. |
contentType | string | MIME type of the file. |
bytes | number | File size in bytes. |
fullPage | boolean or null | Whether the full page was captured. |
device | string or null | Emulated device name, if any. |
viewport | object or null | Viewport width and height in px. |
pageHeight | number or null | Rendered page height in px. |
darkMode | boolean or null | Whether dark mode was emulated. |
cookieBannersHidden | number or null | Number of cookie banners hidden. |
stickyElementsAdjusted | number or null | Sticky headers/footers adjusted for full-page capture. |
adRequestsBlocked | number or null | Ad/tracker requests blocked. |
loginFormDetected | boolean or null | Whether the page showed a login form. |
truncatedAtPx | number or null | Height in px at which the capture was cut (maxHeight, the 20,000 px cap, or the 4,000 px fallback); null if the whole page was captured. |
captureFallback | boolean | True if the full capture timed out and the top 4,000 px were captured instead. |
lazyScrollMs | number or null | Time spent scrolling to load lazy images, ms. |
durationMs | number | Total capture time, ms. |
timingsMs | object or null | Per-step timings, ms. |
takenAt | string | Capture time (ISO 8601). |
The run also saves FAILED_URLS (each failed URL with its error code and reason) and RUN_STATS in the key-value store.
How much does it cost?
Pay per event: you pay only the per-screenshot price below, plus a start fee of $0.00001 per run per GB of memory ($0.00001 at the default 1 GB). Apify platform usage (compute, storage, data transfer) is included, so there is nothing else to pay. Failed captures are free.
| Apify plan | Price per screenshot | Per 1,000 screenshots |
|---|---|---|
| Free | $0.00089 | $0.89 |
| Bronze (Starter) | $0.00083 | $0.83 |
| Silver (Scale) | $0.00074 | $0.74 |
| Gold, Platinum, Diamond (Business+) | $0.00061 | $0.61 |
Example: 1,000 screenshots on the Free plan cost $0.89 in total. Memory can be set from 1 GB (default) to 4 GB; more memory captures more pages in parallel (2 pages per GB) but doesn't change the price.
Use with AI agents, MCP and the API
- MCP: add
https://mcp.apify.com?tools=phaux/website-screenshotsto any MCP client and call it as a tool. The dataset returns a directscreenshotUrlfor each capture. - API:
POST https://api.apify.com/v2/acts/phaux~website-screenshots/run-sync-get-dataset-itemswith{"urls": [...]}returns the items, including file URLs. - Each input field's type, default and allowed values are documented in the input schema.
Data and compliance
- Only public pages are captured, exactly as any visitor sees them. Logins, cookies, custom headers and custom scripts aren't supported, on purpose.
- URLs with embedded credentials and addresses on private or internal networks are refused.
- You are responsible for having the right to capture the pages you submit.
Limits
- Each URL has a hard time limit (
pageTimeoutSecs, default 60 s). Pages that keep the browser busy past it are abandoned and not charged. - Full-page captures stop at 10,000 px by default and at most 20,000 px (
maxHeight). Very long pages are cropped from the top. - Each GB of memory captures 2 pages in parallel (all modes).
- Some sites block automated browsers (HTTP 403). They're reported as failures and aren't charged; some work through the optional proxy.
- For very long pages, JPEG is 5–10× smaller than PNG.
FAQ
- Do I pay for compute or storage on top? No. You pay only the per-screenshot price (and the tiny start fee); Apify platform usage is included.
- Why is my long page cut off? Full-page captures are cropped at 10,000 px by default to keep them fast. Set
maxHeightup to 20,000 px for longer pages. IfcaptureFallbackis true, the full capture timed out and the top 4,000 px were saved instead. - Where are the files? In the run's default key-value store.
screenshotUrlin each dataset item is a direct link. - Can I capture a page behind a login? No. Only public pages are supported.
- Can it tell me when a page changes? Yes. Turn on
visualDiff: each screenshot is compared with the previous one (or with an image you provide), and you get the percent changed and a diff image, at no extra charge. - Something isn't working? Open an issue on the Issues tab with the run ID.