Website Screenshot API: Full-Page PNG, JPEG & PDF avatar

Website Screenshot API: Full-Page PNG, JPEG & PDF

Pricing

from $0.61 / 1,000 screenshots

Go to Apify Store
Website Screenshot API: Full-Page PNG, JPEG & PDF

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

Phaux

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

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-actor with actor phaux/website-screenshots, or load it as its own tool with https://mcp.apify.com?tools=phaux/website-screenshots. Read results with get-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 (with jpegQuality) and pdf (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). truncatedAtPx in 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 (deviceScaleFactor 2 or 3), hiding your own selectors, and ad-network blocking.

Why use it?

Common screenshot problemWhat this Actor does
Failed captures still cost creditsYou'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 spinnersIt waits for load, then up to 3 s for network idle, then web fonts, then your waitForSelector, then delayMs.
Missing lazy-loaded imagesIt scrolls the page quickly (capped by maxScrollMs) and scrolls back to the top before capturing.
Sticky headers repeated or covering contentFixed and sticky elements are shown once at the top by default, or hidden (stickyElements).
Need only part of the pageUse maxHeight, fullPage: false, elementSelector or clip.
Emoji render as boxesColour-emoji and CJK fonts are installed.
Hung runsEach 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

  1. Add one or more page URLs to urls.
  2. Pick a format and, if needed, fullPage, device or darkMode.
  3. Run the Actor. Open the Overview dataset view to see each screenshotUrl, or download all files from the key-value store.
  4. To call it from code, use the Apify API or the MCP server (see below).
  5. 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, default website-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 as urls. For example, use a screenshotUrl from an earlier run, or an approved design export. Set updateBaseline: false to 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"
}
  1. 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.
  2. 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.

  1. Same page, fixed baseline (0PSff9Z2k8reaU8R0): we passed the first run's screenshotUrl in baselineImageUrls with updateBaseline: 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 with elementSelector or clip.
  • Keep the same device, viewport, fullPage and darkMode between 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 sizeChanged is true.
  • PDF output can't be diffed. Use png or jpeg.
  • 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.

FieldTypeDefaultDescription
urlsarrayrequiredPublic web pages to capture (http/https). Duplicates are removed. No login or credentials are supported.
formatstring"png"Image (PNG/JPEG) or a PDF of the page. Allowed: png, jpeg, pdf.
fullPagebooleantrueCapture the whole scrollable page. Off = only the visible viewport.
maxHeightinteger10000Crop 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.
viewportWidthinteger1280Browser window width in CSS pixels (ignored when a device is chosen).
viewportHeightinteger800Browser window height; this is the image height when Full page is off.
deviceScaleFactorstring"1"Device pixel ratio (ignored when a device is chosen). Allowed: 1, 2, 3.
devicestring""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.
darkModebooleanfalseAsk the page for its dark colour scheme (prefers-color-scheme: dark).
hideCookieBannersbooleantrueHide common consent pop-ups (OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics, Sourcepoint and generic cookie bars). Nothing is clicked or accepted.
blockAdsbooleantrueBlock requests to common ad/tracking networks for cleaner, faster captures.
waitUntilstring"load"Navigation event to wait for before the steps below. Allowed: load, domcontentloaded, networkidle.
waitForNetworkIdleMsinteger3000Wait up to this long for network requests to settle (prevents half-loaded screenshots). It never fails the capture.
waitForSelectorstring—CSS selector that must be visible before capturing, e.g. '#main' or '.product-grid'.
waitForSelectorTimeoutSecsinteger10Fail (not charged) if the selector does not appear in time.
delayMsinteger500Fixed delay right before the capture, for animations.
scrollToLoadLazyContentbooleantrueFor full-page captures, scroll down quickly (time-capped) to trigger lazy loading, then scroll back to the top.
maxScrollMsinteger4000Hard cap on scrolling time so long/infinite pages stay fast.
stickyElementsstring"unstick"How fixed/sticky headers and widgets are handled in full-page captures. Allowed: unstick, hide, keep.
hideSelectorsarray—CSS selectors to hide before capturing (chat widgets, banners, ...).
elementSelectorstring—CSS selector; capture only the first matching element.
clipobject—Region in page pixels: {"x":0,"y":0,"width":1280,"height":600}.
jpegQualityinteger80JPEG compression quality from 1 (smallest file) to 100 (best quality). Used only when format is jpeg.
pdfFormatstring"A4"Paper size of the PDF. Used only when format is pdf. Allowed: A4, Letter, Legal, A3, Tabloid.
pdfLandscapebooleanfalsePrint the PDF in landscape orientation. Used only when format is pdf.
pdfPrintBackgroundbooleantrueInclude background colours/images in PDFs.
visualDiffbooleanfalseCompare each PNG/JPEG screenshot with a baseline and add visualDiff (percentChanged, changedArea, diffImageUrl). Off by default; no extra charge.
baselineStoreNamestring"website-screenshots-baselines"Named key-value store in your account that keeps the last screenshot per URL and settings.
baselineImageUrlsarray—Optional baseline image links, in the same order as urls; they take priority over the stored baseline.
updateBaselinebooleantrueSave each new screenshot as the next baseline. Off = keep a fixed reference.
diffPixelToleranceinteger32Per-channel colour difference (0–255) above which a pixel counts as changed.
failOnHttpErrorbooleantrueOn: error pages are not captured and not charged. Off: capture them anyway.
navigationTimeoutSecsinteger30How 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.
maxRetriesinteger1Retries for timeouts and browser errors.
maxConcurrencyinteger—Pages captured at the same time. Default: 2 per GB of memory (2 at the default 1 GB), up to 8.
proxyConfigurationobject{"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.
captureTimeoutSecsinteger—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).
maxLoadWaitMsinteger10000With 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).
detectBlockedPagesbooleantrueTreat bot walls ('Access denied', 'Just a moment...', 'Unknown Error') and blank renders as failures, so you are not charged for them.
pageTimeoutSecsinteger—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

FieldTypeDescription
urlstringThe URL you submitted.
finalUrlstring or nullURL after redirects.
httpStatusnumber or nullHTTP status of the page.
titlestring or nullPage title.
screenshotUrlstringDirect URL of the saved screenshot in the run's key-value store.
keystringKey-value store record key of the screenshot.
formatstringpng, jpeg or pdf.
contentTypestringMIME type of the file.
bytesnumberFile size in bytes.
fullPageboolean or nullWhether the full page was captured.
devicestring or nullEmulated device name, if any.
viewportobject or nullViewport width and height in px.
pageHeightnumber or nullRendered page height in px.
darkModeboolean or nullWhether dark mode was emulated.
cookieBannersHiddennumber or nullNumber of cookie banners hidden.
stickyElementsAdjustednumber or nullSticky headers/footers adjusted for full-page capture.
adRequestsBlockednumber or nullAd/tracker requests blocked.
loginFormDetectedboolean or nullWhether the page showed a login form.
truncatedAtPxnumber or nullHeight 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.
captureFallbackbooleanTrue if the full capture timed out and the top 4,000 px were captured instead.
lazyScrollMsnumber or nullTime spent scrolling to load lazy images, ms.
durationMsnumberTotal capture time, ms.
timingsMsobject or nullPer-step timings, ms.
takenAtstringCapture 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 planPrice per screenshotPer 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-screenshots to any MCP client and call it as a tool. The dataset returns a direct screenshotUrl for each capture.
  • API: POST https://api.apify.com/v2/acts/phaux~website-screenshots/run-sync-get-dataset-items with {"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 maxHeight up to 20,000 px for longer pages. If captureFallback is 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. screenshotUrl in 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.