Website Screenshot Generator - $3.00 per 1,000
Pricing
from $3.00 / 1,000 screenshot takens
Website Screenshot Generator - $3.00 per 1,000
Give it a list of URLs, get a rendered PNG or JPEG of each page: viewport or full page, 320-2560 px wide, 1x/2x/3x density, dark mode, mobile layout. A CSS selector takes out the cookie banner. One row per page: image link, final URL, title, status. Failed pages aren't charged.
Pricing
from $3.00 / 1,000 screenshot takens
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Website Screenshot Generator
Give it a list of URLs and you get back a rendered picture of each page, plus a row of data about it: the URL it finally landed on, the page title, the HTTP status, the image dimensions, the file size and how long the render took.
Each page is opened in a real Chromium, so what you get is the page a visitor sees, with the JavaScript run and the lazy images pulled in. You set the viewport, whether it's the first screen or the whole scrolled page, the pixel density, dark mode, a mobile layout, and what gets taken off the page before the shutter fires.
Price
$3.00 per 1,000 screenshots, plus a $0.004 start fee per run.
| Screenshots | Total |
|---|---|
| 100 | $0.304 |
| 1,000 | $3.004 |
| 10,000 | $30.004 |
One screenshot-taken event per picture of the page you actually asked for. Not charged: the sample
row, duplicate addresses (dropped before rendering), a page that timed out or refused, a page that
answered with an anti-bot check instead of the page, and any page skipped because the run hit the
size budget you set. Those all come back as rows with "charged": false so you can see what
happened.
Filter on charged == true and the count equals what you were billed for.
Input
{"urls": ["https://www.python.org","https://developer.mozilla.org","https://news.ycombinator.com"],"viewportWidth": 1440,"viewportHeight": 900,"fullPage": false,"format": "jpeg","quality": 80,"removeSelectors": ["#cookie-banner", ".cookie-consent"],"maxItems": 10}
| Field | What it does |
|---|---|
urls | Pages to photograph, one per line. A bare domain like example.com works. Up to 300 per run; duplicates dropped before anything renders. |
maxItems | Hard stop on how many pages this run captures, whatever the list length. |
fullPage | Off gives you the viewport. On scrolls the page and stitches it into one tall image, up to the height ceiling. |
viewportWidth / viewportHeight | The window the page lays out in. 1440x900 is a laptop, 1920x1080 a desktop, 390x844 a phone. Width 320–2560, height 200–4000, and the schema rejects anything outside that. |
deviceScaleFactor | 1 normal, 2 retina, 3 print. 2x is four times the file size, 3x is nine times. |
darkMode | Tells the page the visitor prefers a dark scheme. Sites with a dark theme render in it; sites without look identical. |
mobile | Touch device profile and a mobile user agent, so you get the responsive layout. Pair with a narrow width. |
format / quality | JPEG at 80 is the default and right for almost everything. PNG for lossless or a transparent background. |
waitUntil / delayMs / navigationTimeoutMs | How ready the page must be, how long to pause after, when to give up. Raise delayMs for a heavy single-page app. |
scrollToBottom | Scrolls to the foot first so lazy images below the fold are actually there. Turned on automatically with fullPage. |
selector | A CSS selector to photograph one element instead of the page — a pricing table, a chart, a hero. |
hideSelectors / removeSelectors | Hide keeps the space, remove takes the element out of the layout. Remove is the one for cookie banners and pop-ups; hide is the one for a sticky header you want gone without the layout shifting. |
customCss | Raw CSS injected just before capture, up to 4,000 characters. |
transparentBackground | PNG only. |
locale / timezone | en-US, Europe/Berlin. For sites that localise or print clocks. |
maxFullPageHeight | Where a whole-page capture gets cut. Default 8,000 px, max 20,000. |
maxTotalImageMb | The run stops writing images past this and says so in an uncharged row. Default 250 MB. |
concurrency | Pages rendering at once. 3 is a good balance. Drop to 1 if a site objects to several requests at a time. |
useProxy | Off by default, and off is usually right. Turn it on if a site answers the container with an anti-bot check instead of the page. |
proxyUrls | Your own proxy servers, if you have them. Takes precedence over everything else. Metered per-gigabyte proxy groups are never used, whatever the input asks for. |
Empty input gives you one labelled sample row, free.
Output
{"ok": true,"charged": true,"recordType": "screenshot","url": "https://example.com/","screenshotUrl": "https://api.apify.com/v2/key-value-stores/r7tznlACMo9u7atq8/records/screenshot-001-example.com.jpg?signature=...","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": 1220,"scrapedAt": "2026-08-21T16:20:52.314Z"}
Where the images live
Each picture goes into the run's key-value store. screenshotUrl is a direct HTTPS link you can put
in an <img> tag, drop in a spreadsheet or fetch from a script; screenshotKey is the file name.
File names are numbered by position in your list and tagged with the domain, so ten pages give you
screenshot-001-example.com.jpg through screenshot-010-... and they sort the way you sent them.
The images last as long as your account keeps the run's data. On the free plan that's a limited window, so copy anything you want to keep into your own storage.
Keeping file sizes sane
Pictures get big faster than people expect. A whole-page capture of a long article at 2x is many times the size of that page's first screen at 1x, because you're multiplying the height by the density.
The defaults already lean small. JPEG at quality 80 is the one that matters most; it's visually
clean and a fraction of the file at quality 100. Leave deviceScaleFactor at 1 unless somebody is
going to zoom in. maxFullPageHeight cuts a whole-page capture at 8,000 px, which is what stops an
infinite-scroll feed rendering until something gives way. maxTotalImageMb caps the run on top of
all that.
Limits
- Pages behind a login are out of scope. The run carries no accounts and no cookies, so it sees the logged-out page. A paywall or sign-in screen is what you'll get a picture of.
- Some sites refuse automated browsers outright. Across a battery of 50 well-known public pages, 48
rendered and 2 answered with an anti-bot check — and those 2 still refused through the rotating
pool, so the pool isn't the fix for them. Your own proxy servers in
proxyUrlsare. Either way you get the image of the block page and an unchargedBLOCKEDrow instead of a bill for a picture of the wrong thing. - Every page is stopped once it has painted rather than being allowed to load indefinitely. That's what keeps a batch of marketing sites from taking minutes each, but a page that fills in content after that point shows the state at the moment of the stop.
- A full-page capture is cut at the height ceiling. An infinite-scroll feed always gets cut; the row
says
truncated: trueand gives you the realpageHeight. - Video and audio are blocked, so an autoplaying hero video shows its poster frame. Analytics and session-recording scripts are blocked too — that doesn't change how a page looks, but a site that refuses to render until its tag manager loads is the rare exception.
- PDFs and other non-HTML addresses aren't rendered. The browser treats them as a download and you
get an uncharged
NAV_ABORTEDrow. - Dark mode only asks the site for its dark theme. A site with no dark theme looks the same.
- Fonts, ads and personalised content vary by where a request comes from, so two runs of the same page a day apart won't be pixel-identical. Compare content, not hashes.
- Image dimensions cap at 16,000 px per side, and a total surface ceiling quietly lowers the full-page height when you combine a wide viewport with 3x density. The row reports what you actually got.
- 300 pages per run is the hard ceiling.
Diagnostic codes
Uncharged rows carry "_diagnostic": true and an errorCode: BLOCKED (anti-bot check served
instead of the page — the image is attached anyway so you can see it), NAV_TIMEOUT, DNS_FAILED,
CONNECTION_REFUSED, TLS_FAILED, SELECTOR_NOT_FOUND, IMAGE_TOO_LARGE, BUDGET_REACHED,
TIME_BUDGET. Each names the url it belongs to and says what to change.
Questions
How do I get rid of the cookie banner? Put its CSS selector in removeSelectors —
#onetrust-banner-sdk, .cookie-consent, whatever the site uses.
Why is my full-page screenshot cut off? It was taller than maxFullPageHeight, 8,000 px by
default. The row says truncated: true. Raise it to 20,000 if you need the rest.
Will one broken page fail the run? No. It becomes an uncharged diagnostic row and the run moves on. A failed run would still bill the start fee, which would mean paying to be told something went wrong.
Can I schedule it? Yes. Nothing is held between runs. Keep the screenshotUrl off each run and
you end up with a dated history of what the page looked like.