# Full Page Screenshot API for Lazy-Loaded Pages (`lone_rachis/full-page-website-screenshot`) Actor

Full page screenshot API with a completeness check: it scrolls each page so lazy-loaded sections appear, finds blank bands in the image, repairs them and scores the result from 0 to 100. A page it cannot capture costs nothing.

- **URL**: https://apify.com/lone_rachis/full-page-website-screenshot.md
- **Developed by:** [Kesav Kumar Jayakumar](https://apify.com/lone_rachis) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 screenshots

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Full Page Website Screenshot do?

**Full Page Website Screenshot** takes a **full-page screenshot** of a public web page, including the parts that only load as a visitor scrolls, and tells you whether the image is complete. Give it a list of URLs. It opens each page in Chrome, scrolls in steps so lazy-loaded images and scroll-triggered sections appear, captures the whole page from the top, then scans the image for blank areas and repairs them. With the default settings every captured page gets a completeness score from 0 to 100 and a plain status, so you know which screenshots to trust without opening them one by one. The score is left empty when you turn off the check for blank areas, choose the `simple` capture strategy or capture only the first screen. A page that could not be captured has no image and no score: its row carries a status and a reason instead. You pay only for pages it captured. A page that is blocked, fails to load or is disallowed by robots.txt costs nothing.

Use it as a **screenshot API**: start it from code, a schedule or an integration, then fetch the images and the result table over HTTP. It works on public pages only. It does not log in, take cookies from you, solve CAPTCHAs, hide that it is an automated browser or get around bot protection. When a site refuses access, the row says so and you pay nothing for it.

### Why use Full Page Website Screenshot?

A plain full-page screenshot breaks on modern sites. Images wait for a scroll before they load, and sections fade in only while they are on screen. The picture comes back with white holes, sometimes thousands of pixels tall, and nothing tells you. In our 20-site test, a plain full-page capture left a blank band of 500 px or more on 7 sites. This Actor scrolls the page the way a visitor would, scans the finished image for gaps and repairs them. On those same 7 sites the scroll pass and the repair pass together removed the gap on 5, in each of four live runs. On the other 2 (gsap.com and lenis.darkroom.engineering) a gap stayed in every run, and the Actor reported it with the status `partial`, a completeness score and the position of the band instead of hiding it. In one of the four runs a further site (theguardian.com) kept a band too. The Actor does not promise a complete image on every page. It tells you which ones are not.

What you get:

- **Fewer blank gaps** on lazy-loaded and scroll-animated pages. The Actor scrolls in steps, promotes lazy images, waits for images and fonts, then captures from the top.
- **A completeness check** on every full-page image at the default settings. Tall blank bands are found and re-captured by scrolling back to them. Bands that stay blank are listed with their position instead of being hidden.
- **Honest statuses.** `ok`, `partial`, `blocked`, `failed` or `skipped`, each with a reason. Only `ok` and `partial` screenshots are charged.
- **Control over the capture.** Viewport size, retina pixel ratio, phone emulation, dark mode, PNG, JPEG or WebP, cookie banner hiding, hidden elements, a wait for a selector.
- **Tall pages.** Pages are captured in tiles and stitched, so a tall page comes out as one image. The default cut is 20,000 px. A 30,000 px page is stitched correctly once `maxPageHeight` is raised, which the setting allows up to 60,000 px.

Each claim above has a test behind it:

| What you get | How it works | The test that backs it |
| --- | --- | --- |
| **Blank gaps found and repaired** | Steps through the page, loads `data-src` and native lazy images, re-captures blank bands it finds and reports any band it could not fill, with its position. | Four live runs on 20 public sites on 11 Oct 2026 (`gate-final-e`, `gate-final-f`, `gate-verify-k1`, `gate-audit-g`): a plain full-page capture left a band of 500 px or more on 7 sites, the Actor removed the gap on 5 of them in every run and marked the other 2 `partial`. Local tests: "data-src and native lazy images all load" and "reveal-on-view sections that hide again on leave are repaired into the full image". |
| **No charge for a page it did not capture** | Blocked, failed, HTTP-error, robots-disallowed and unsafe-address rows are written with a reason and are not charged. | "B1 one screenshot event is charged per delivered result, and failed, blocked and skipped rows are not charged". |
| **A spending cap that stops the run** | Set a maximum cost per run. The run stops before it charges past it, and every URL it did not reach gets a `skipped` row. | "P6 the maximum charge per run stops the run cleanly: no screenshot is charged past the limit", and the same at three pages at a time. |
| **robots.txt always respected** | There is no switch to turn it off. A disallowed URL is skipped, listed and not charged. A robots.txt that cannot be read closes the site. | "robots.txt is always honoured, even if a user sends respectRobotsTxt false" and the robots.txt tests of the review fixes. |
| **No requests to private networks** | Localhost, private ranges and cloud metadata addresses are refused, also when a public page redirects there or embeds them, and in other spellings of the same address. | The three I7 tests: a redirect to an internal address, the same over https, and an embedded frame or image. A full-width or ideographic-dot spelling of 127.0.0.1 is refused too. |
| **Restarts that never charge twice** | When the platform migrates or aborts a run, the counters are saved. A result already delivered is not captured or charged twice. An aborted run stops where it is, so URLs it had not reached get no row. | "P1 on migrating the run saves its summary and state..." and "P2 on aborting the run saves a summary and exits well inside 30 seconds...", both driven by the platform's own events. |

Plus what the Apify platform adds around it:

- **API access.** Start runs and read results with the Apify API or the JavaScript and Python clients.
- **Scheduling.** Run it hourly or daily to archive pages or watch them change.
- **Integrations.** Send results to Make, Zapier, Google Sheets, Slack or any webhook.
- **Monitoring.** Run history, logs and alerts for failed runs.

Typical uses are page archives for compliance, visual checks of landing pages on desktop and phone, competitor page monitoring, link preview thumbnails and design research boards.

### What data can Full Page Website Screenshot extract?

Each URL becomes one row in the dataset. The most useful fields:

| Field | Type | What it holds |
| --- | --- | --- |
| `url` | string | The URL you asked for. |
| `status` | string | `ok`, `partial`, `blocked`, `failed` or `skipped`. |
| `screenshotUrl` | string | Link to the image file in the run's key-value store. |
| `completenessScore` | integer | Share of the image that is not blank, 0 to 100. It is `null` on a row without an image, and when the check did not run (check for blank areas off, `simple` strategy, or first screen only). |
| `title` | string | Page title, cleaned and cut to 300 characters. |
| `httpStatus` | integer | HTTP status code of the page. |
| `widthPx`, `heightPx` | integer | Image size in device pixels. |
| `blankBands` | array | Blank bands left in the image, as pixel ranges from the top. |
| `qualityFlags` | array | Notes such as `blank-band-remaining`, `images-pending`, `height-capped`, `http-error-status` or `internal-request-blocked`. |
| `durationMs` | integer | Time spent on this URL. |
| `error` | string | Why a URL has no screenshot, in a sentence for people. |
| `errorCode` | string | A short code for the same reason, for counting rows by cause. It is `null` on a captured page. The codes are listed below. |

Every row that has no screenshot carries one of these codes in `errorCode`, so you can count rows by reason without reading the sentence. The sentence in `error` can be reworded in a later version. The code stays.

| `errorCode` | Meaning |
| --- | --- |
| `robots-disallowed` | The site's robots.txt does not allow the page, or a redirect led to a path it does not allow. |
| `robots-unreadable` | The robots.txt of the site could not be read, so the site is treated as closed. |
| `private-address` | The address, a redirect or the robots.txt address leads inside a network. |
| `invalid-url` | The text is not a web address, or is longer than 2,048 characters. |
| `duplicate` | The same page appears earlier in the list. |
| `charge-limit` | The run reached the maximum cost per run before this URL. |
| `run-time-limit` | The run reached its time limit before or while this URL was captured. |
| `repeated-timeouts` | The run stopped after several pages in a row ran out of time. |
| `run-ended` | The run ended while this page was being captured. |
| `blocked` | The site answered with an access-denied or bot-check page. |
| `http-error` | The page answered with an HTTP error status such as 404 or 500. |
| `dns-error` | The domain name does not exist. |
| `connection-failed` | The server refused or closed the connection. |
| `unreachable` | The server could not be reached. |
| `tls-error` | The site certificate is not valid. |
| `redirect-loop` | The page redirects in a loop. |
| `download` | The URL is a file download, not a web page. |
| `page-timeout` | The page did not finish loading in time. |
| `capture-timeout` | The capture took longer than the time limit per page. |
| `selector-invalid` | The `waitForSelector` value is not a valid selector. |
| `too-large` | The page transferred more data than one page may (500 MB). |
| `other` | Any other reason. The sentence in `error` says what happened. |

### How to take a full page screenshot of a website

1. Open the Actor in Apify Console and select the **Input** tab.
2. Add the pages you want under **Page URLs**. The form is prefilled with two example pages, so you can press **Start** to see a result straight away.
3. Choose the **Image format** and the viewport. The defaults give a PNG at 1280 px wide.
4. Keep **Check for blank areas** and **Repair blank areas** on. They are what makes the image complete.
5. Press **Start**. In our local tests a typical page took about 14 seconds (median 12.1 to 14.1 s over four runs on a laptop limited to one CPU) and the heaviest animated page in the test, a WebGL site, 61 to 100 seconds. These figures come from that laptop, not from the Apify platform, where the time may be shorter or longer.
6. Open the **Output** tab for the table with every screenshot, or the **Storage** tab to download the images. Export the table as JSON, CSV or Excel.

To run it from code, send the same input to the Actor through the API:

```json
{
    "startUrls": [{ "url": "https://apify.com" }, { "url": "https://en.wikipedia.org/wiki/Web_scraping" }],
    "format": "jpeg",
    "quality": 85,
    "viewportWidth": 1440,
    "colorScheme": "dark"
}
```

### How to save screenshots to Google Sheets, Google Drive or Slack (Make, Zapier, no code)

A common use is a weekly archive of the same pages, such as your own pricing page or a set of landing pages. Create a schedule with your list of URLs, then pass each run's results on.

**Slack, built in.** On the Actor's **Integrations** tab, add **Slack**, connect your workspace, pick a channel and choose the event "Run succeeded". Each finished run posts a message with a link to its results.

**Google Sheets or Drive with Make.com.**

1. In Make, create a scenario and add the Apify module that watches for finished Actor runs, set to this Actor.
2. Add the Apify module that gets dataset items, and map the run's default dataset ID.
3. Add Google Sheets "Add a Row" with `url`, `title`, `screenshotUrl` and `completenessScore`, or an HTTP "Get a file" step on `screenshotUrl` followed by Google Drive "Upload a File" to keep the images themselves.

**Zapier.** Use the Apify trigger for a finished Actor run, then the Apify step that fetches dataset items, then a Google Sheets "Create Spreadsheet Row" or a Slack "Send Channel Message" action.

**Your own code.** Add a webhook on the **Integrations** tab for the event "Run succeeded", and read the dataset from the URL in the payload.

### How much does it cost to take a full page screenshot?

You pay per screenshot, and the Apify platform usage for the run is included, Apify Proxy traffic too. A screenshot costs $0.02 on the Free and Bronze plans, so 1,000 pages cost $20.

| Event | When it is charged | Price |
| --- | --- | --- |
| `screenshot` | One captured page with status `ok` or `partial` | $0.02 (Free, Bronze), $0.018 (Silver), $0.016 (Gold) |
| Actor start | Once per run, scaled by memory (Apify standard event) | $0.00005 per GB of memory |

Pages that are blocked, fail to load, return an HTTP error such as 404 or 500, are skipped by robots.txt or are rejected as unsafe addresses cost nothing. Silver and Gold plans pay less per screenshot, as the table shows. Bronze pays the same as Free. You can cap a run with the **Maximum cost per run** setting, and the Actor stops cleanly at that limit.

#### How much does one screenshot cost?

One screenshot costs $0.02 on the Free and Bronze plans, $0.018 on Silver and $0.016 on Gold. A run adds a start fee of about $0.0002 at the default memory. The price already includes the Apify platform usage and any Apify Proxy traffic, so there is no second bill for compute. A run of 100 pages costs about $2. You can set **Maximum cost per run** to cap the spend, and the Actor stops cleanly when the cap is reached.

#### How do I keep a run within budget?

Set **Maximum cost per run** when you start it. The run stops before it would charge past that amount, and every URL it did not reach gets a `skipped` row with the code `charge-limit`, so nothing is lost silently. Capturing many URLs in one run pays the start fee once.

#### What does the price pay for?

Each page gets a scroll pass, a wait for images and fonts, a scan for blank areas, a repair pass where needed and a completeness score. Heavy animated pages take longer than plain ones, and the price stays the same for both. A `partial` result is a saved image with a known gap, and it is charged, because it is a usable capture. The flags in `qualityFlags` and the positions in `blankBands` say where the gap is.

### Input

Open the **Input** tab to see every setting with a short description. The first fields are `startUrls`, `fullPage` (capture the full page, on by default), `format` (PNG, JPEG or WebP) and `quality` (for JPEG and WebP). The form has four groups after them:

- **Viewport and device:** `viewportWidth`, `viewportHeight`, `deviceScaleFactor` (pixel ratio), `mobile` (phone emulation) and `colorScheme`.
- **Completeness check:** `captureStrategy`, `verifyCompleteness`, `repairBlankAreas`, `blankAreaThresholdPx` and `scrollDelayMs`.
- **Page loading:** `waitUntil`, `waitForSelector`, `extraDelayMs`, `maxPageHeight`, `captureErrorPages`, `hideCookieBanners`, `hideSelectors` and `freezeAnimations`.
- **Limits and proxies:** `maxConcurrency`, `timeoutSecs` and `proxyConfiguration` (Apify Proxy with data center addresses only).

`startUrls` accepts plain URLs, added one by one or pasted with **Bulk edit**, one per line. A link to a text file is not supported: the run stops at once with a message that asks you to paste the URLs, because the Actor does not download lists from addresses it has not checked. One run takes at most 1,000 URLs, so split a bigger list into several runs, and a URL longer than 2,048 characters is skipped with a row that says so. A URL that appears more than once is captured once, and each extra copy gets a `skipped` row that names the first one. Set `captureStrategy` to `simple` for a single plain shot when speed matters more than completeness.

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. The screenshots are separate files in the run's key-value store. A run also writes a `SUMMARY` record with the counts of captured, partial, blocked, failed and skipped URLs. Every URL of a valid list gets exactly one row, also when the run stops early at the cost cap, after five timeouts in a row or near the time limit of the run: the URLs it did not reach get a `skipped` row that says why. A list that is empty or has a blank address is refused before anything runs. A run that the platform kills from outside, for example because it ran out of memory, can leave URLs without a row; start it again and the results already delivered are kept. A run in which no page could be captured ends with the status Failed and the most common reason in its message, and the rows stay in the dataset. If a run is restarted, a result that was already delivered is not captured or charged a second time.

A captured page and a blocked page look like this:

```json
[
    {
        "inputIndex": 0,
        "url": "https://example.com/pricing",
        "finalUrl": "https://example.com/pricing/",
        "httpStatus": 200,
        "title": "Example Pricing Page",
        "status": "ok",
        "screenshotUrl": "https://api.apify.com/v2/key-value-stores/exampleStoreId0001/records/screenshot-3f2a9c1b7d4e.png",
        "format": "png",
        "widthPx": 1280,
        "heightPx": 5240,
        "bytes": 842113,
        "blankBands": [],
        "blankBandsFound": 2,
        "blankBandsRepaired": 2,
        "completenessScore": 100,
        "qualityFlags": [],
        "durationMs": 9400,
        "error": null,
        "errorCode": null
    },
    {
        "inputIndex": 1,
        "url": "https://example.org/members",
        "httpStatus": 403,
        "status": "blocked",
        "screenshotUrl": null,
        "completenessScore": null,
        "error": "The site returned an access-denied or bot-check page. Not captured, not charged. The Actor does not retry through other networks or disguise itself.",
        "errorCode": "blocked"
    }
]
```

### Tips for faster and cheaper screenshots

- Capture several URLs in one run. The browser start and the Actor start charge are paid once per run, not once per page.
- Use `jpeg` or `webp` with a quality near 80 when you do not need lossless images. On the 19 pages captured in one of our 20-site runs, JPEG at quality 80 was 3.6 times smaller than PNG at the median (range 0.8 to 7.7 times), and WebP 4.5 times smaller (range 0.9 to 8.9 times, on the 16 pages short enough for WebP). Pages that are mostly flat color or text gain little, and one came out larger as JPEG. WebP cannot hold an image taller than 16,383 px, so a taller page is saved as PNG and flagged `format-fallback-png`.
- Lower `scrollDelayMs` for fast sites and raise it when lazy content arrives late. The default is 160 ms.
- Set `maxPageHeight` to what you need. Endless feeds stop at that height instead of running for minutes.
- Keep `deviceScaleFactor` at 1 unless you need sharp retina images. A ratio of 2 gives four times the pixels and needs more memory and time. In our local test the widest setting (3840 px at a ratio of 3, an image of 100 million pixels) peaked at about 3.2 GB for the whole browser, against about 2.5 GB for the default settings, so give a run with such settings the 8,192 MB option. A heavy animated page at a ratio of 3 also ran past the 150 second limit once on one CPU, and that page was not charged.
- Use `hideSelectors` for chat widgets and sticky bars, and `waitForSelector` when a page paints its main content late.
- Raise `maxConcurrency` only together with the Actor memory setting. Every parallel page opens its own browser tab, and the Actor holds the number to the run memory divided by 1 GB.

### FAQ, disclaimers and support

#### Is it legal to take screenshots of websites?

Taking a screenshot of a public page is what any visitor's browser does, but the law depends on the site, the content and what you do with the image. Terms of use, copyright and database rights can apply to the pages and to how you reuse the pictures. Check them for your use case. Images, text and logos on a page usually belong to the site or to others. You are responsible for how you use the screenshots. Do not use the Actor to capture illegal content; report misuse to Apify at legal@apify.com. This is general information, not legal advice.

#### Does Full Page Website Screenshot respect robots.txt?

Yes, always. URLs that a site's robots.txt disallows are skipped, listed with the status `skipped` and not charged, and so is a page that redirects to a closed path. The Actor reads the file under its own name, `FullPageWebsiteScreenshot`, not under a browser name, and follows RFC 9309: a file that answers with a 4xx code means the site has no rules, and a file that cannot be read (a server error or no answer after one retry) means the site is closed, so its pages are skipped with the reason and not charged. If you own a site and want it captured, allow the path in its robots.txt.

#### Why is my screenshot marked partial?

A `partial` row means the image was saved but something is known to be incomplete. Look at `qualityFlags`: `blank-band-remaining` (a blank area survived the repair, with its position in `blankBands`), `images-pending` (images were still loading) or `wait-selector-timeout` (your selector never appeared). The image is still charged, because it is a usable capture. Raise `scrollDelayMs`, add an `extraDelayMs`, or raise `blankAreaThresholdPx` if the page has large solid-color sections on purpose.

#### Why was my URL blocked?

Some sites answer automated browsers with an access-denied or bot-check page. The Actor does not try to defeat that. The row gets the status `blocked`, and nothing is charged. The Actor does not retry through other networks or disguise itself.

#### Are error pages such as 404 charged?

No. A URL that answers with an HTTP error (404, 410, 500 and similar) gets the status `failed` with the code in the `error` field, and nothing is charged. This keeps a mistyped URL from costing you money. Turn on `captureErrorPages` to take the screenshot anyway. Those pages are then charged like any other, and flagged `http-error-status`.

#### Does it open private or internal addresses?

No. The Actor refuses addresses inside a network (localhost, private ranges, cloud metadata addresses), also when a page redirects there or embeds them, and also for the robots.txt request. Every request the Actor makes, the browser's and its own, goes through the same address check. Such a URL gets the status `skipped` and is not charged. An embedded item that points inside is left out of the image, and the row carries the flag `internal-request-blocked`.

#### Can it capture pages behind a login?

No. It captures what a visitor sees without signing in. It takes no cookies, passwords or tokens from you and never signs in.

#### What happens when a run reaches its time limit?

The Actor reads the time limit of the run from the platform. About two and a half minutes before it, no new page is started. Pages in progress get until 30 seconds before the limit to finish, and then every URL that was not delivered gets a `skipped` row that says the run reached its time limit, so you can run those URLs again. Nothing is charged for them. Set a longer **Timeout** in the run options for a long list: at about 20 seconds a page, 1,000 URLs need hours.

#### How long can one page take?

One attempt takes at most 250 seconds with the defaults. That is 90 seconds for loading (60% of **Time limit per page**, up to 90 seconds), 150 seconds for the capture after it (the full **Time limit per page**) and 10 seconds that the browser library adds around the two. The robots.txt read of a site happens inside that same bound, so a slow robots.txt cannot add to it. A page that runs out of time is not retried and is not charged, and five of them in a row stop the run. A page that fails fast for a reason that can change, such as a dropped connection, is tried once more.

#### What if a page never stops sending data?

A page that sends more than 500 MB while it loads is closed. Its row gets the status `failed` and the code `too-large`, it is not tried again and it is not charged. The 20 sites in our test sent 127 MB in total, so a normal page stays far below the limit.

#### How tall can a page be?

By default the image is cut at 20,000 CSS pixels, and `maxPageHeight` can raise that to 60,000. Very tall pages at a high pixel ratio are cut earlier, at about 100 million pixels per image, to keep the run inside its memory. A cut page gets the flag `height-capped`.

#### Can I schedule screenshots and send them to other apps?

Yes. Use Apify schedules for recurring runs, and integrations or webhooks to pass the dataset to Make, Zapier, Google Sheets, Slack or your own endpoint. The same runs are available through the API.

#### What if something looks wrong?

Open the Issues tab on the Actor page and describe the URL, your input and what you expected. A run link helps. Issues are answered within two days.

#### Is personal data involved?

A screenshot shows whatever the page shows, which can include names, faces, email addresses or other personal data. The Actor stores the image, the page title and technical details of the capture. It does not pull personal data out into fields, sign in, or accept consent banners; hiding a banner only hides it from the picture. Under the GDPR and similar laws you are the controller of what you capture, so you need a lawful reason to capture and keep pages that show people, and archiving or journalism may carry their own rules.

### Other Actors by the same developer

- [SEC EDGAR Filing Monitor](https://apify.com/lone_rachis/sec-edgar-filing-monitor): new SEC filings for the tickers or CIKs you watch.
- [SEC Form D Feed](https://apify.com/lone_rachis/sec-form-d-raises-feed): new private fundraising rounds filed with the SEC on Form D, with amounts and industry.
- [SEC XBRL Fundamentals](https://apify.com/lone_rachis/sec-xbrl-fundamentals): revenue, EPS, cash flow and other reported figures per company and period, from SEC XBRL filings.
- [UK Company Check](https://apify.com/lone_rachis/uk-company-check): Companies House status, outstanding charges and risk flags for UK companies, or a list of newly registered ones.
- [US Trademark Status and Watch](https://apify.com/lone_rachis/us-trademark-status-watch): USPTO status and upcoming deadlines for US trademarks, and what changed since your last run for marks you watch.
- [New Scholarly Papers Watch](https://apify.com/lone_rachis/scholarly-papers-watch): papers new since your last run for the keywords, ORCID authors, journals, funders or DOIs you watch, from Crossref.

# Actor input Schema

## `startUrls` (type: `array`):

Public web pages to capture, one screenshot per URL. Add them one by one, or paste a list with Bulk edit, one URL per line. Links to text files are not supported: paste the URLs instead. One run takes at most 1,000 URLs. Repeated addresses are captured once and listed as duplicates.

## `fullPage` (type: `boolean`):

Capture the whole page from top to bottom. Turn it off to capture only the first screen at the viewport height.

## `format` (type: `string`):

File type of each screenshot. PNG is lossless and the largest. JPEG and WebP are usually several times smaller on photo-heavy pages and use the quality setting below.

## `quality` (type: `integer`):

Image quality from 1 to 100 for JPEG and WebP. Ignored for PNG.

## `viewportWidth` (type: `integer`):

Width of the browser window in CSS pixels. The screenshot is this wide, multiplied by the pixel ratio.

## `viewportHeight` (type: `integer`):

Height of the browser window in CSS pixels. Sets the page layout for viewport-sized sections and the height of a first-screen capture.

## `deviceScaleFactor` (type: `integer`):

Device pixel ratio. Use 2 for sharp retina images. The image gets 2 times wider and taller, and the run needs more memory and time.

## `mobile` (type: `boolean`):

Load the page as a mobile browser with touch input. Pair it with a viewport width of 390 to 430 px.

## `colorScheme` (type: `string`):

Light or dark appearance. Sites that follow the browser setting switch to their dark theme.

## `captureStrategy` (type: `string`):

Auto scrolls the page so lazy images and scroll animations load, then takes the full-page image. Simple takes one plain full-page shot and is faster, but long pages can come out with blank areas.

## `verifyCompleteness` (type: `boolean`):

Scan each image for tall blank bands and give it a completeness score from 0 to 100. Works with the auto strategy.

## `repairBlankAreas` (type: `boolean`):

Scroll back to each blank band, take a fresh viewport shot and paste it into the image. Needs the completeness check.

## `blankAreaThresholdPx` (type: `integer`):

A blank band counts only when it is at least this tall. Raise it if the page has large solid-color sections on purpose.

## `scrollDelayMs` (type: `integer`):

Time to wait at each scroll step so lazy content can load. Raise it for slow sites. Lower values run faster.

## `waitUntil` (type: `string`):

Which browser event ends the page load before the scroll step starts. The load event suits most pages. Network idle waits longer and can time out on pages that never stop loading.

## `waitForSelector` (type: `string`):

Optional CSS selector, such as #main or .hero-image. The capture waits up to 15 seconds for it to appear. Leave empty to skip.

## `extraDelayMs` (type: `integer`):

Fixed pause in milliseconds after the page is loaded and scrolled, for intros and animations that need a moment to finish.

## `maxPageHeight` (type: `integer`):

Tallest image to produce in CSS pixels. Longer pages are cut at this height and flagged. Endless feeds stop here. At a high pixel ratio the cut can come earlier, at about 100 million pixels per image.

## `captureErrorPages` (type: `boolean`):

Take a screenshot even when the page answers with an HTTP error such as 404 or 500. Off by default, so a mistyped URL is reported as failed and is not charged.

## `hideCookieBanners` (type: `boolean`):

Hide common cookie consent banners and overlays from well-known consent tools so they do not cover the page.

## `hideSelectors` (type: `array`):

CSS selectors of elements to hide before the capture, for example a chat widget or a sticky promo bar.

## `freezeAnimations` (type: `boolean`):

Stop CSS animations and transitions at their end state, so the image does not catch a half-finished motion.

## `maxConcurrency` (type: `integer`):

How many pages to capture in parallel, from 1 to 10. Every parallel page opens its own browser tab and needs extra memory and processor time, so raise the Actor memory when you raise this: the Actor holds the number to the memory of the run divided by 1 GB. The default of 1 suits the default 4096 MB, which is one CPU core: several heavy pages on one core are slower than one after the other.

## `timeoutSecs` (type: `integer`):

Longest time to spend on capturing one page, in seconds: scrolling, waiting for images and repair. Loading the page has its own limit of 60% of this value, at most 90 seconds, and the browser library adds 10 seconds, so one attempt can take up to 250 seconds at the default. A page that runs out of time is not retried and is not charged. After 5 pages in a row run out of time, in the loading or in the capture, the run stops and lists the rest as skipped.

## `proxyConfiguration` (type: `object`):

Optional. Apify Proxy with data center addresses only. Residential proxies and your own proxies are not accepted, and the run stops with a message if you pick one. Proxy traffic is included in the price per screenshot.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping"
    }
  ],
  "fullPage": true,
  "format": "png",
  "quality": 80,
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "deviceScaleFactor": 1,
  "mobile": false,
  "colorScheme": "light",
  "captureStrategy": "auto",
  "verifyCompleteness": true,
  "repairBlankAreas": true,
  "blankAreaThresholdPx": 500,
  "scrollDelayMs": 160,
  "waitUntil": "load",
  "waitForSelector": "",
  "extraDelayMs": 0,
  "maxPageHeight": 20000,
  "captureErrorPages": false,
  "hideCookieBanners": true,
  "hideSelectors": [],
  "freezeAnimations": true,
  "maxConcurrency": 1,
  "timeoutSecs": 150,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset with one row per URL: status, completeness score, size and the screenshot link.

## `files` (type: `string`):

Key-value store keys: every screenshot image, plus the SUMMARY and STATE records.

## `summary` (type: `string`):

Counts of captured, partial, blocked, failed and skipped URLs for this run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://apify.com"
        },
        {
            "url": "https://en.wikipedia.org/wiki/Web_scraping"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lone_rachis/full-page-website-screenshot").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [
        { "url": "https://apify.com" },
        { "url": "https://en.wikipedia.org/wiki/Web_scraping" },
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("lone_rachis/full-page-website-screenshot").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call lone_rachis/full-page-website-screenshot --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lone_rachis/full-page-website-screenshot"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/yzLSoCh38VpQXC0Lb/builds/WNl1WPAG1rZyykIlO/openapi.json
