Request a tool
All toolsAutomationsGuidesMCP serverRequest a toolPlatformsCategories
Website Screenshot Generator icon

Website Screenshot Generator

Take website screenshots in bulk. Give a list of URLs, get a PNG or JPEG per page. Full page or viewport, 320-2560px, dark mode, HTTP status.

105 runs on Apify $0.003 per screenshot taken ($3 / 1,000)
Run this in the cloudRun on Apify →

Developer & Research Tools

How it works

  1. 1
    Open it on Apify

    Hit Run on Apify — it opens the tool in the cloud, no install.

  2. 2
    Set the inputs

    Adjust urls, fullPage, viewportWidth (sensible defaults are pre-filled).

  3. 3
    Click Run

    The tool runs on Apify’s cloud and collects the data for you.

  4. 4
    Export the results

    Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.

Pricing

$0.003 per screenshot taken = $3 per 1,000

You are charged forWhenPrice
Screenshot takenCharged once per rendered screenshot delivered to the dataset: the image file and its direct link, the final URL after redirects, the page title, the HTTP status, the image and page dimensions, the file size and the render time. Pages that time out, refuse the connection, fail DNS, return an anti-bot check or match no element for your selector are never charged, and neither are duplicate URLs, the sample row an empty run returns, or pages skipped once the run hits your image-size budget.$0.003

Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-08-17, and they are what you are actually charged.

Inputs

FieldWhat it doesType
urlsOne or more pages to photograph, one per line. A bare domain like example.com works too. Up to 300 per run, and duplicates are dropped before anything is charged.array
fullPageOff: you get exactly the viewport, like the first screen a visitor sees. On: the page is scrolled and stitched into one tall image, down to the height ceiling below.boolean
viewportWidthBrowser window width the page is laid out at. 1440 is a typical laptop, 1920 a desktop monitor, 390 a phone. Between 320 and 2560.integer
viewportHeightBrowser window height. This is the image height unless "Capture the whole page" is on. Between 200 and 4000.integer
deviceScaleFactor1 for a normal screen, 2 for a retina-quality image at twice the pixels on each axis, 3 for print. Remember that 2x is four times the file size and 3x is nine times.integer
darkModeTells the page the visitor prefers a dark colour scheme. Sites that ship a dark theme will render it; sites that do not are unchanged.boolean
mobileRenders as a touch phone with a mobile user agent, so you get the responsive layout. Pair it with a narrow viewport width such as 390.boolean
formatJPEG is far smaller and right for almost everything. PNG is lossless and supports a transparent background.string
qualityOnly applies to JPEG. 80 is visually clean at about a third of the size of 100. Lower it to fit more pages inside the run's size budget.integer
waitUntilHow ready the page must be before the shutter fires. "domcontentloaded" is the fast default. "load" waits for images and stylesheets. "networkidle" waits for traffic to stop, which on an ad-funded page can mean waiting for the timeout. "commit" fires almost immediately.string
delayMsPause after the page is ready, to let animations finish and fonts swap in. 800 ms suits most sites; raise it for a heavy single-page app.integer
navigationTimeoutMsGive up on a page that has not become ready in this long. The page still gets an uncharged row explaining the timeout.integer
scrollToBottomScrolls to the foot of the page first so lazy-loaded images below the fold are actually there in the picture. Turned on automatically when you capture the whole page.boolean
maxFullPageHeightThe tallest a whole-page capture may get before it is cut off. Protects you from an endless feed turning into a 60,000 pixel image. Rows tell you when a picture was cut.integer
maxTotalImageMbThe run stops taking pictures once it has written this many megabytes and writes one uncharged row saying so. Nothing is charged for the pages it skipped.integer
maxItemsHard stop on how many pages this run will photograph, whatever the list length. Keep it low while you are testing - you pay per screenshot.integer
selectorA CSS selector. Fill it in to photograph just that element - a pricing table, a hero banner, a chart - instead of the page. Left empty, the whole viewport or page is captured.string
hideSelectorsCSS selectors to make invisible before capturing, while keeping the space they occupy. Good for a sticky header you want gone without the layout shifting.array
removeSelectorsCSS selectors to take out of the layout entirely. This is the one for cookie banners, chat bubbles and newsletter pop-ups.array
customCssRaw CSS injected just before the picture is taken. Anything you can write in a stylesheet works, up to 4,000 characters.string
transparentBackgroundPNG only. Leaves the page background out of the image, which is what you want when capturing a single element to drop into a design.boolean
localeThe language the browser asks for, as a code such as en-US, de-DE or fr-FR. Sites that localise will render in that language.string
timezoneAn IANA time zone such as Europe/Berlin or America/New_York, for pages that print dates or clocks.string
concurrencyHow many pages render simultaneously. 3 is a good balance. Lower it to 1 if a site you are capturing objects to several requests at once.integer
useProxyTurn it on if a site you are capturing refuses the run.boolean
proxyUrlsLeave this empty unless you already pay for proxy servers and want the traffic to leave through them, in the form http://user:pass@host:port. Anything listed here takes precedence.array

What you get

A structured dataset — each result includes fields like:

urlscreenshotUrlfinalUrltitlestatusCodeimageWidthimageHeightformatfullPagefileSizeBytesloadTimeMs

Export every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.

Related tools in Developer & Research Tools

Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.

GitHub Scraper iconDeveloper & Research Tools

GitHub Scraper

Search GitHub repos and users: stars, forks, language, topics, licence, plus user bio, company and followers. No token needed. $0.90 per 1,000 rows.

18 use cases

Stack Overflow / Stack Exchange Scraper iconDeveloper & Research Tools

Stack Overflow / Stack Exchange Scraper

Search Stack Overflow and Stack Exchange by keyword or tag. Score, answer count, views, reputation and body text. $2 per 1,000 questions.

2 use cases

Package Registry Scraper (npm + PyPI) iconDeveloper & Research Tools

Package Registry Scraper (npm + PyPI)

Get npm and PyPI package metadata as JSON. Version, license, author, repo, keywords and npm monthly downloads. $2 per 1,000 packages.

2 use cases

arXiv Scraper iconDeveloper & Research Tools

arXiv Scraper

Search arXiv papers by title, author, abstract or category. Get full abstracts, authors, categories, DOI, dates and PDF links. $2 per 1,000 papers.

2 use cases

OpenAlex Scholarly Works Scraper iconDeveloper & Research Tools

OpenAlex Scholarly Works Scraper

Search 250M+ OpenAlex papers with no API key. Get titles, authors, venue, year, citations, DOI, OA links and full abstracts. $2.00 per 1,000 papers.

2 use cases

Crossref Scholarly Works Scraper iconDeveloper & Research Tools

Crossref Scholarly Works Scraper

Search 150M+ papers on Crossref: DOI, title, authors, journal, publisher, date, citations and abstract. No API key. $1.00 per 1,000 works.

2 use cases

See all Developer & Research Tools →

Website Screenshot Generator: a picture of every page in your list, PNG or JPEG

Paste a list of addresses and you get an image of each page, plus a row carrying the link to that image, the final URL after redirects, the page title, the HTTP status, the dimensions and the file size.

You control what the camera sees: the first screen or the whole page stitched together, any width from 320 to 2,560 pixels, normal or retina density, light or dark, desktop or phone layout. CSS selectors let you delete the cookie banner and the chat bubble before the shutter fires, or photograph one element on its own.

Worth knowing before the first run. A page that answers 404 or 500 and still renders is a real screenshot and is charged like any other, with statusCode on the row to tell you. A page that refuses to render at all still gets its image stored and handed to you, and that one is not charged.

InputPage addresses, up to 300 per run
OutputOne row per page, with a link to its image
Ceiling300 pages per run, inside a total image size budget you set
Account neededNone
Price$3.00 per 1,000 screenshots, which is $0.003 each, flat on every plan

📸 What Website Screenshot Generator does

It opens each address in a real browser at the size you asked for, waits as long as you told it to, applies your CSS, and takes the picture. Images land in the run's key-value store and every row links straight to its own.

Full-page capture scrolls the page and stitches it into one tall image, up to the height ceiling you set, and marks truncated when it had to cut. Scrolling also happens on request without full-page capture, which is what makes lazy-loaded images below the fold actually appear.

The selector fields are where most of the work happens in practice. removeSelectors takes an element out of the layout, which is the one for cookie banners and pop-ups. hideSelectors makes it invisible but keeps its space, which is right for a sticky header you want gone without everything shifting up. selector narrows the shot to one element.

locale and timezone are passed to the browser, so a site that localises renders in the language and clock you asked for.

Duplicate addresses are dropped before anything renders, so a messy list does not cost twice.

📥 What you give it

{
  "urls": ["https://example.com", "https://news.ycombinator.com"],
  "fullPage": true,
  "viewportWidth": 1440,
  "format": "jpeg",
  "quality": 80,
  "removeSelectors": ["#cookie-banner", ".intercom-launcher"],
  "maxItems": 10
}
FieldComes set toWhat it is
urlstwo examplesThe pages, one per line. A bare domain works. Up to 300.
maxItems10Hard stop on how many pages this run photographs, 1 to 300. Keep it low while testing.
fullPagefalseOff gives you exactly the viewport. On scrolls and stitches the whole page.
viewportWidth, viewportHeight1440, 900The browser window. 390 wide is a phone, 1920 a desktop monitor.
deviceScaleFactor12 is retina, 3 is print. Remember 2x is four times the file size.
format, qualityjpeg, 80JPEG is much smaller. PNG is lossless and can carry transparency. Quality applies to JPEG only.
darkMode, mobilefalseAsk the page for its dark theme, and render as a touch phone. Pair mobile with a narrow width.
waitUntildomcontentloadedHow ready the page must be: commit, domcontentloaded, load or networkidle. On an ad-funded page networkidle often waits for the timeout.
delayMs800Extra pause for animations and fonts, up to 15 seconds.
navigationTimeoutMs25000Give up on a page that has not become ready in this long. If enough of the page exists by then, it is still captured.
scrollToBottomfalseScroll first so lazy images load. On automatically with fullPage.
maxFullPageHeight8000Tallest a full-page shot may be before it is cut, up to 20,000 px.
maxTotalImageMb250The run stops once it has written this many megabytes. Pages it never reached are not charged.
selectoremptyA CSS selector to photograph one element instead of the page.
hideSelectors, removeSelectorsemptyUp to 30 selectors each: hide keeps the space, remove takes it out of the layout.
customCssemptyRaw CSS injected just before the shot, up to 4,000 characters.
transparentBackgroundfalsePNG only. Leaves the page background out, for dropping an element into a design.
locale, timezoneemptyen-US, de-DE, Europe/Berlin, America/New_York.
concurrency3Pages rendered at once, 1 to 6. Drop to 1 for a site that objects.
useProxyfalseTurn it on if a site refuses the run.
proxyUrlsemptyYour own servers, as http://user:pass@host:port. Only the first entry in the list is used, and it takes precedence over everything else.

Leave urls empty and you get one sample row showing the shape, with no browser started and no screenshots charged.

📤 What you get back

A real row from a real run:

{
  "ok": true,
  "charged": true,
  "recordType": "screenshot",
  "url": "https://example.com/",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/zBdffYZdgUJdUcRAq/records/screenshot-001-example.com.jpg?signature=9w6b5...",
  "screenshotKey": "screenshot-001-example.com.jpg",
  "finalUrl": "https://example.com/",
  "title": "Example Domain",
  "statusCode": 200,
  "imageWidth": 1440,
  "imageHeight": 900,
  "format": "jpeg",
  "fullPage": false,
  "darkMode": false,
  "deviceScaleFactor": 1,
  "viewportWidth": 1440,
  "viewportHeight": 900,
  "pageHeight": 900,
  "truncated": false,
  "fileSizeBytes": 17536,
  "loadTimeMs": 1090,
  "scrapedAt": "2026-09-21T01:27:34.234Z"
}
FieldWhat it is
screenshotUrl, screenshotKeyA direct link to the image, and its name in the run's key-value store. Download what you want to keep.
url, finalUrlWhat you asked for, and where it ended up after redirects.
statusCodeThe main document's status. A page that rendered on a 404 says 404 here.
imageWidth, imageHeightRead from the image itself, so this is the real picture size, density included.
pageHeight, truncatedHow tall the document was, and whether the height ceiling cut it.
fileSizeBytes, loadTimeMsUseful for spotting the page that is quietly eating your size budget.
format, fullPage, darkMode, deviceScaleFactor, viewportWidth, viewportHeightThe settings this shot was taken with, copied onto the row, so a mixed dataset stays readable.

🧾 Reading the output

recordType and ok separate the three kinds of row. charged is the flag that marks a real screenshot apart from the sample and the diagnostics, rather than a receipt.

RowHow to spot itCharged
A screenshotrecordType is screenshot, ok is trueyes
The sample row_sample is trueno
A diagnostic_diagnostic is true, with an errorCodeno

The table view has no errorCode column, so a failed row can look like a thin successful one. A BLOCKED row even carries an image. Filter on recordType when you are counting.

CodeWhat it means
BLOCKEDThe site would not let the page render. The image of whatever was on screen is still delivered.
NAV_TIMEOUTNothing usable had loaded inside navigationTimeoutMs.
NAV_ABORTEDNot a page the browser can display. A PDF or other file lands here.
DNS_FAILED, CONNECTION_REFUSED, TLS_FAILEDThe address did not resolve, the server refused, or the certificate did not check out.
SELECTOR_NOT_FOUNDYour selector matched nothing on the page.
IMAGE_TOO_LARGEThe picture went past the encoder's ceiling of 16,000 pixels a side.
BUDGET_REACHEDmaxTotalImageMb is spent. One row says so and the pages after it are skipped.
TIME_BUDGETThe run ran out of time before reaching that page.
RENDER_FAILED, RENDERER_CRASHEDThe browser failed on that page. Worth one re-run.
PROXY_INPUT_ADJUSTEDA network option you set was not one this actor uses, so it carried on without it.

▶️ How to run it

1. Open Website Screenshot Generator and click Try for free. 2. Put your addresses into Page addresses, one per line. 3. Set Maximum screenshots low for the first run, so you can check the framing before paying for 300 of them. 4. Add the cookie banner and chat bubble to Remove these elements. That one change improves more screenshots than any other setting here. 5. Click Start, then open the rows to see the images, or pull them from the key-value store.

💰 How much does it cost?

$3.00 per 1,000 screenshots, which is $0.003 each. Flat on every Apify plan, no volume tiers.

You pay per image taken. The sample row is not charged, nor are the diagnostics: a page that was refused, timed out with nothing to show, had no matching selector, or was skipped once the size budget ran out. A page that rendered is charged whatever its status code says.

Ten screenshots is three cents. The whole 300 is ninety.

💡 What people use it for

  • Thumbnails for a directory or a link roundup, generated from the list you already have.
  • Before and after shots of a redesign, same width, same settings, two runs.
  • Visual regression checks on a schedule: same pages, same size, compare the images.
  • Capturing one element cleanly, a pricing table or a chart, with a transparent background for a

deck.

  • Checking how a set of pages looks on a phone, dark mode on, without touching a device.
  • Evidence and archiving, with finalUrl, statusCode and a timestamp on every row.

🚧 What it does not do

  • Nothing behind a login. No cookies, no sign-in, no sessions.
  • 300 pages per run. Split a longer list, or schedule it.
  • The page is frozen once it has painted, so content that arrives very late can be missing. Raise

delayMs or use load or networkidle when that matters.

  • Height and size ceilings. 20,000 pixels of page by your setting, 16,000 pixels a side at the

encoder, and the total megabytes you allowed.

  • No PDF output. PNG and JPEG only.
  • No text extraction. For the words on the page, use the crawler linked below.
  • It cannot make a site render. A page that refuses gives you the image of the refusal, free.
  • Only the first entry in your own server list is used.

🧭 Which site tool do you need?

If you wantUse
Pictures of pagesThis one
The same pages as text, Markdown and chunksWebsite Intelligence Crawler
Repositories and developer profilesGitHub Scraper
Package metadata and download countsnpm + PyPI Package Scraper

❓ Questions people ask

How do I get rid of the cookie banner? Put its CSS selector into Remove these elements. Open the site, inspect the banner, copy the id or class.

Why is my full-page shot cut off? It hit maxFullPageHeight. The row says truncated: true. Raise the ceiling, but remember an endless feed has no bottom.

Can I screenshot one element? Yes, with selector. Pair it with PNG and a transparent background to drop it straight into a design.

Where do the images live? In the run's key-value store, linked from screenshotUrl on every row. Download the ones you want to keep.

Why do two runs of the same page look different? Fonts, animations and ads settle at different speeds. Raise delayMs, or switch waitUntil to load, and the shots get more repeatable.

Is screenshotting a public page legal? It photographs public pages as a visitor sees them. What you do with the images afterwards is subject to copyright and the site's terms. Apify's write-up on the legality of web scraping is a good starting point, and we are not lawyers.

🆘 If something breaks

Open the Issues tab on the actor page. Send the address and the run ID. If a diagnostic row landed, its errorCode and details usually name the reason already.