Website Screenshot Studio avatar

Website Screenshot Studio

Pricing

from $2.00 / 1,000 successful captures

Go to Apify Store
Website Screenshot Studio

Website Screenshot Studio

Capture websites as PNG, JPEG, or PDF on desktop, tablet, and mobile. Automatically dismiss consent dialogs and popups, with bounded lazy loading, explicit errors, and an HTML gallery.

Pricing

from $2.00 / 1,000 successful captures

Rating

0.0

(0)

Developer

Falak Fatma

Falak Fatma

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 days ago

Last modified

Categories

Security

Limited permissions

Share

Capture batches of websites as PNG, JPEG, or PDF on desktop, tablet, and mobile. Every unique URL × device produces a dataset row, including failed captures. Images and PDFs are stored in the run's key-value store, alongside a gallery and run summary.

Pricing

The capture fee is $0.002 per successful file ($2 per 1,000). PNG, JPEG, full-page, element, and PDF captures use the same fee. One URL captured on three devices produces three billable files. A multipage PDF counts as one file. Retries do not add capture fees, and failed captures or HTTP-error diagnostic images have no capture fee.

Apify's automatic startup event is $0.00005 per allocated GB, with a minimum of one event. At 4 GB that is $0.0002 per run. The live Pricing tab shows whether compute, storage, transfer, and optional proxy costs are included or billed separately. If metered separately, those costs and the startup event can still apply when a capture fails.

Set Max cost per run in Apify to limit spending. The Actor stops starting captures when the remaining event budget cannot fund another successful file; skipped jobs receive BUDGET_EXCEEDED rows without artifacts. Native spending limits may stop a run earlier, leaving partial results.

This is an independent implementation inspired by Apify's Website Screenshot Generator. The docs/AUDIT.md explains the design choices and tradeoffs.

Quick start locally

Requires Node.js 22 or newer.

npm ci
npm run browsers:install
npm run demo
npm run preview

Open http://127.0.0.1:4321. The demo uses a local fixture with desktop and mobile pages, a redirect, a lazy image, and an intentional HTTP 404. It needs no account or API token. Four of its six captures should succeed; the other two show error handling.

To capture a real website:

npm start -- --input examples/basic.json
npm run preview

Use a fresh storage directory to preserve previous results:

CRAWLEE_STORAGE_DIR=./storage/my-run npm start -- --input examples/mobile.json
CRAWLEE_STORAGE_DIR=./storage/my-run npm run preview

The SDK clears default run storage at startup. Copy results elsewhere or use a different directory for each run. The preview server binds only to this computer.

Set SCREENSHOT_PREVIEW_PORT to run a separate gallery alongside an existing one:

CRAWLEE_STORAGE_DIR=./storage/fleet-sites SCREENSHOT_PREVIEW_PORT=4322 npm run preview

The running local preview is accessible only on this computer. The gallery itself is also a production output: on Apify, each run saves GALLERY.html and its screenshot files in cloud storage. Generated public or signed record links can grant access to people holding those links, so cloud output should not be assumed private solely because it came from a private actor.

Input

{
"urls": [{ "url": "https://example.com" }],
"devices": ["desktop", "mobile"],
"format": "png",
"fullPage": true,
"scrollToBottom": true,
"cookieConsent": "reject",
"dismissModals": true,
"maxConcurrency": 2,
"maxRetries": 1
}

urls accepts strings or objects containing only url. Use explicit HTTP(S) addresses. Repeated normalized URLs and devices are deduplicated; fragments remain distinct for applications with hash routing. The Actor does not follow links or expand URL-list files. Unknown input fields fail validation.

OptionDefaultBehavior
devices["desktop"]Any combination of desktop, tablet, mobile
formatpngpng, jpeg, or pdf
quality85JPEG quality, 1–100
fullPagetrueFull page up to the image height limit; false captures the viewport
viewportWidth / viewportHeight1440 / 900Desktop viewport; tablet is 768 × 1024, mobile 390 × 664
maxScreenshotHeight12000Image height cap; cropped images have truncated: true
captureSelectoremptyCapture the first visible matching element; unavailable for PDF
waitUntilloadload, domcontentloaded, or networkidle
waitForSelectoremptyRequire a visible element before capture
delay500Additional wait after navigation, in milliseconds
navigationTimeoutSecs30Navigation deadline per attempt
captureTimeoutSecs60Entire capture deadline per attempt
assetTimeoutSecs10Wait for images in the capture area to load and decode, allowing the image set and page height to stabilize
failOnMissingImagestrueReturn ASSET_LOAD_FAILED without a screenshot if a required image remains unavailable; false saves a diagnostic capture with issues
scrollToBottomfalseTrigger lazy content, then return to the top
maxScrollTimeSecs10Scrolling deadline, also bounded by the image height cap
cookieConsentrejectPrefer rejecting optional cookies; fall back to accept/close when needed. accept reverses the preference; none preserves consent overlays
dismissModalstrueClose other detected modals through an explicit close, dismiss, or no-thanks control
hideCookieBannersfalseHide known banner elements; does not click consent
selectorsToHideemptyCSS selectors, one per line; runtime also accepts a string array
darkModefalseRequest the browser dark color scheme
blockMediatrueBlock video/audio downloads while retaining images and fonts
maxConcurrency2Isolated contexts running in parallel, up to 8
maxRetries1Extra attempts, up to 3
maxCaptures100Reject input above this URL × device count; maximum 1000
proxyomittedOptional Apify or custom proxy configuration
allowPrivateUrlsfalseLocal testing only; rejected on Apify

The Actor uses full Chromium in its new headless mode. Desktop uses a browser-version-matched Chrome user agent; mobile and tablet use device user agents and touch emulation. All images use a device scale factor of 1, so dimensions describe CSS pixels. This is Chromium emulation, not a physical device or Safari test. Proxy connections share one session within each capture attempt; retries request a fresh session.

All duration fields ending in Secs use seconds. delay uses milliseconds. PDF uses the screen stylesheet and prints the complete document to A4 pages, respecting a site's CSS page size. PDF ignores the image height cap and JPEG quality; fullPage must be true. Its image width and height are null. Element screenshots fail if they exceed the image size limit.

Retries apply to navigation errors, capture deadlines, HTTP 429, HTTP 5xx, and transient image-loading failures, with short incremental backoff. When a proxy is configured, HTTP 403 also retries with a fresh proxy session. An HTTP/2 protocol error switches the next configured retry to a separate HTTP/1.1 browser and records a warning; this does not guarantee that a site will accept the connection. Other HTTP 4xx errors and permanent image decoding failures are final. A ready-selector failure is final. The default maximum capture time is approximately two 60-second attempts plus backoff, browser startup, and storage operations. The whole-run timeout is configured separately in Apify run options. Deadline errors retain known navigation and image metadata and identify the active capture stage.

Consent handling runs before scrolling and again before capture, including a brief check for delayed dialogs. Finite animations finish before these checks, so their completion handlers can expose dialogs before screenshot encoding. Hidden and offscreen iframes do not consume the visible-frame scan limit. The Actor uses actual controls inside detected consent dialogs and prefers rejection by default. It retries a control to allow for delayed page hydration, and can accept or close when the preferred control is unavailable or ineffective. Other detected modals use only explicit close/dismiss controls. An unresolved blocker produces OVERLAY_BLOCKED with its detected controls and no screenshot; configured retries use fresh contexts. A blocker that persists through all attempts remains a failure. Set cookieConsent: "none" and dismissModals: false when the original overlay state is intentional. hideCookieBanners and selectorsToHide remain explicit visual-hiding overrides, applied before automatic dismissal.

Working live-site inputs are included for examples/prada.json and examples/gucci-residential.json. The Gucci example uses a US residential proxy, one capture at a time, up to three retries, and domcontentloaded followed by explicit image readiness checks. Proxy use remains an input choice.

Image readiness uses the chosen capture area: full-page images up to the height cap, the current viewport, or the selected element. CSS-hidden and fully clipped images are excluded, as are images outside that area. Relevant native lazy images are loaded eagerly; common data-src and data-srcset placeholders are initialized. Scrolling uses instant steps so site-wide smooth scrolling cannot prevent distant sections from being reached. The Actor waits for decoding and a short stable image/layout window. An unresolved required image fails the capture by default, including a source URL and HTTP/decoding reason in assets.issues. Diagnostic mode preserves those issues and saves the image for investigation.

Output

Each dataset item includes:

{
"id": "deterministic-url-and-device-id",
"startUrl": "https://example.com/",
"url": "https://example.com/",
"device": "desktop",
"format": "png",
"ok": true,
"httpStatus": 200,
"title": "Example Domain",
"screenshotKey": "capture-desktop-<id>.png",
"screenshotUrl": "<signed-or-public-Apify-storage-URL>",
"screenshotPath": null,
"width": 1440,
"height": 900,
"pageHeight": 900,
"truncated": false,
"bytes": 12345,
"sha256": "<content-hash>",
"attempts": 1,
"durationMs": 1400,
"capturedAt": "<ISO-timestamp>",
"error": null,
"errorType": null,
"warnings": [],
"overlayActions": [],
"assets": {
"totalImages": 3,
"relevantImages": 1,
"loadedImages": 1,
"pendingImages": 0,
"failedImages": 0,
"ignoredHiddenImages": 1,
"ignoredOutsideCapture": 1,
"fontsReady": true,
"issues": []
}
}

This example describes the fields; values are illustrative. Locally, screenshotUrl is null and screenshotPath points to the actual file. On Apify, screenshotPath is null and the SDK supplies the storage URL, including a signature when required. Preserve the full URL.

A captured HTTP error page has ok: false, errorType: "HTTP_ERROR", its status code, and a diagnostic screenshot when the capture can otherwise complete. A navigation, selector, unresolved-overlay, or required-image failure has no screenshot by default. Warnings identify invalid hide selectors, bounded scrolling, cropping, or incomplete assets in diagnostic mode. ok reports HTTP and capture success; a bot challenge returned with HTTP 200 can still be marked successful.

overlayActions records each clicked control, for example { "kind": "cookie-consent", "action": "reject", "button": "Reject Non-Essential" }. The gallery shows those actions alongside the capture. When an overlay cannot be dismissed, the error row retains known HTTP status and actions but has no binary artifact.

assets reports loaded/relevant image counts and excluded image counts. Each issue includes url, alt, state, reason, and available httpStatus and contentType. The gallery displays image readiness and issue reasons. assets is null when a capture fails before reaching the asset checks. Counts can change between runs as a page adds or removes images.

The key-value store contains:

  • capture-<device>-<id>.<extension> — image or PDF.
  • RESULTS — the complete result array, in URL/device order.
  • SUMMARY — success/failure counts and elapsed time.
  • GALLERY.html — visual gallery, including errors.

The dataset streams completed rows, so its order may differ from the input order. A partial-success batch finishes successfully. When every capture fails, the Actor saves its results and exits with an error. Storage or browser infrastructure failures also fail the run. An externally aborted run can leave a partial dataset without a final gallery.

Tests

npm run check
npm test
npm run test:integration
npm run build
npm run smoke

Integration tests use Chromium and local fixtures. They inspect image pixels and dimensions, PDF signatures, redirects, HTTP failures/retries, lazy loading, cropping, selector behavior, capture deadlines, and infinite-scroll bounds. Overlay tests cover reject/accept preferences, accept-only consent, delayed and iframe dialogs, modal close controls, opt-out, and explicit failure when a blocker remains. They also verify that unrelated Accept All buttons are left alone. Asset tests cover slow decoding/loading, hidden and clipped images, viewport/element boundaries, deferred sources, smooth-scroll interference, real HTTP/decoding failures, bounded deadlines, diagnostic mode, and retries. The live smoke test additionally checks example.com and apify.com; it requires network access and can fail when either site changes or blocks automation.

For a deployed Actor, run the opt-in cloud suite against an explicit build:

npm run test:cloud -- --build 0.1.14 --report storage/cloud-tests/fresh-verification

The suite uses APIFY_TOKEN or the existing Apify CLI 1.10.0 keyring login. It starts bounded, billable cloud runs in the authenticated owner's account, downloads artifacts, and checks pixels, dimensions, hashes, result completeness, output links, validation, and expected failures. Some runs deliberately finish with FAILED; the test passes when the recorded behavior matches the case. Public fixture services and live sites must be reachable. --list prints the cases without using credentials or starting runs. Reusing the same report directory resumes saved run IDs and skips verified cases. Use a new directory for a fresh retest.

The named famous-*, fixed-*, gucci-*, and proxy cases require explicit selection with --only; they are excluded from the default suite. See the docs/TIMEOUT-FIX.md for the current release evidence and working site inputs. Previous results remain in the docs/FAMOUS-SITES-AUDIT.md.

Deploy and publish

The docs/RELEASE.md covers GitHub, a private Apify deployment, a cloud smoke test, and Store publication. The Dockerfile installs the Chromium version associated with the lockfile. npm ci reproduces the dependency tree.

This repository does not deploy automatically. GitHub CI runs the local checks and browser tests. No token is needed for local development. Use GitHub/Apify's normal credential storage or environment variables when deploying, and keep tokens out of source files.

Limits and tradeoffs

  • A screenshot records what the browser rendered. Login walls, bot challenges, and undetected overlays can still appear. Detected blocking dialogs must be cleared and required images must be ready before a default capture succeeds. The Actor does not solve CAPTCHAs or sign in.
  • Image readiness checks DOM image elements in the main document; CSS backgrounds, canvas/WebGL content, video frames, embedded frame content, and arbitrary application animation state are not certified by the image counts. Video/audio downloads remain blocked by default. Asset waits are bounded by assetTimeoutSecs and the total capture deadline. Diagnostic mode can intentionally save incomplete images with explicit issues.
  • Overlay detection uses dialog semantics, known consent containers, and English control labels. Custom implementations, other languages, closed shadow roots, or dialogs appearing after the last check can require site-specific handling. Explicit CSS hiding can alter layout and does not record consent.
  • The height limit controls image output and scrolling, while PDF prints the whole document. Large PDFs and heavy pages still need memory and a sensible whole-run deadline.
  • Normal captures share one Chromium process; an HTTP/1.1 fallback process starts only after an HTTP/2 protocol error. Each attempt has its own clean context, and both browsers close at run completion. There is no persistent queue, automatic migration resume, browser-crash recovery, visual diffing, or baseline history in this first version.
  • Public-address checks block private/reserved targets and subresources as a best effort. DNS rebinding and proxy-side DNS resolution prevent this from being a network security boundary. Deploy only in an environment with suitable network isolation.
  • SHA-256 hashes identify byte-identical files. Dynamic content and metadata can change hashes; a hash difference is not a visual change score.
  • Apify compute, storage, transfer, and optional proxy usage follow the live Pricing tab's platform-cost setting. Retention and later storage access follow the account's storage policy.

Source code is independently written. The reference actor's branding and documentation are not used as this product's own.