Picpail — Bulk Image Downloader: All Images from URLs to ZIP
Pricing
Pay per event
Picpail — Bulk Image Downloader: All Images from URLs to ZIP
Download all images from web pages or image URLs into one ZIP, full-size originals instead of thumbnails: img, srcset, lazy-load, CSS, og:image. Real format and pixel size, duplicate removal, size/format filters, monitor mode. $0.0005 per image; duplicates and skips free.
Pricing
Pay per event
Rating
0.0
(0)
Developer
CyberMax
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 hours ago
Last modified
Categories
Share
Picpail: Bulk Image Downloader — All Images from URLs to ZIP
Download all images from any web page, or a list of image URLs, into one ZIP. Picpail finds every picture a
visitor would see or click through to (<img>, srcset, lazy-load attributes, <picture>, CSS backgrounds,
og:image, JSON-LD product images, gallery links to originals), swaps thumbnails for the full-size originals
on Shopify, WordPress, Wikimedia, Cloudinary, Wix, Squarespace, Contentful and imgix, and downloads each file once.
Every image is checked from its bytes (real format, width and height), duplicates are dropped by SHA-256, and you
get a ZIP with a folder per page plus one data row per image. $0.50 per 1,000 images; duplicates, filtered-out
images and failures are free.
Use it for: product photo downloads for a catalogue or marketplace migration, competitor image audits, backing up a site's media before a redesign, building image datasets, grabbing every photo from a gallery or blog post, and checking alt text across pages.
Why Picpail
| Picpail | Typical image downloader | |
|---|---|---|
| Thumbnails → full-size originals | Yes (Shopify, WordPress, Wikimedia, Cloudinary, Wix, Squarespace, Contentful, imgix) | No: you get the 300 px copy the page shows |
Lazy-loaded images (data-src, data-srcset, data-lazy-src …) | Yes | Often missed |
| Real format, width, height, bytes, SHA-256 per image | Yes, read from the file | Guessed from the HTML, or none |
| Duplicates removed | By URL and by file content | Rarely |
| Filters (min width/height, formats, file size, URL regex, same site) | Yes; filtered images are free and big files are cut short after the header | Few |
| One ZIP, split into parts for big jobs | Yes, streamed to disk (steady memory on any job size) | Varies |
| Monitor mode (only new images since the last run) | Yes | No |
| Price | $0.0005 per image | $0.00089–$0.002 per image, or $0.07 per page URL |
Benchmark (Apify, 24 Sep 2026, same 3 pages: books.toscrape.com, wordpress.org/news, an Allbirds product page):
| Actor | Result | Time | Price for this job* |
|---|---|---|---|
| Picpail | 67 images, one 18 MB ZIP + a row per image (format, size, SHA-256, alt) | 4.2 s | $0.034 |
| getascraper/bulk-image-downloader | 72 files (the same pictures; 5 WordPress photos fetched twice at two sizes), no ZIP | 6.7 s | $0.064 |
| onescales/bulk-image-downloader | one 18 MB ZIP, no per-image data | 36.7 s | $0.21 (free tier, $0.07 per URL) |
| crawlerbros/website-image-scraper | image URLs only (no files), every srcset size listed separately | 3.3–6.4 s per page | $0.20 |
* Each Actor's published price for the Apify free tier on 24 Sep 2026. With full-size originals switched on (the default, added after this benchmark), the Allbirds page returns 2000–4000 px product photos instead of 300 px copies.
Ready-made inputs (first try in one click)
Every product image on a page, as one ZIP (the Store's default input; skips icons and tiny images):
{ "urls": ["https://books.toscrape.com/"], "minWidth": 100, "minHeight": 100 }
Only JPEG/PNG/WebP images, as a metadata list (links, sizes, formats) instead of a ZIP:
{ "urls": ["https://books.toscrape.com/"], "output": "list", "formats": ["jpeg", "png", "webp"], "minWidth": 100 }
Watch a page and download only new images each run (pair with a daily Schedule):
{ "urls": ["https://books.toscrape.com/"], "monitor": true, "monitorKey": "books-home" }
Example
Input:
{"urls": ["https://books.toscrape.com/","https://wordpress.org/news/","https://www.allbirds.com/products/mens-tree-runners"],"minWidth": 100,"minHeight": 100}
One dataset row per image:
{"type": "image","pageUrl": "https://wordpress.org/news/","pageTitle": "WordPress News – The latest news about WordPress and the WordPress community","imageUrl": "https://i0.wp.com/wordpress.org/news/files/2024/01/sunita-rai-featured-img.jpg?ssl=1","pageImageUrl": "https://i0.wp.com/wordpress.org/news/files/2024/01/sunita-rai-featured-img.jpg?w=1920&ssl=1","source": "srcset","alt": "Sunita Rai at WordCamp Asia","format": "jpeg","mimeType": "image/jpeg","width": 1920,"height": 1200,"bytes": 1408399,"sha256": "0b8801fead7b4a693ec6c4e13ec5ac1c0ed25b2872428fbf829b5c649c670494","fileName": "002-wordpress.org_news/0002-sunita-rai-featured-img.jpg","zipFile": "images.zip","zipUrl": "https://api.apify.com/v2/key-value-stores/<your-run-store>/records/images.zip?signature=…","via": "direct","downloadedAt": "2026-09-24T11:39:38.560Z"}
The OUTPUT record has the ZIP link(s), totals and a line per page (images found, saved, duplicates, filtered,
failed, and why a page failed). More: examples/three-pages-one-zip.json.
Input
| Field | Default | What it does |
|---|---|---|
urls | required | Page URLs and/or direct image URLs, mixed. Bare domains get https://. |
output | zip | zip (one ZIP, a folder per page), zipPerPage, files (each image in the key-value store with its own link) or list (metadata only). |
minWidth, minHeight | 0 | Skip smaller images (measured from the file). 100 skips icons and thumbnails. |
formats | all | e.g. ["jpeg", "png", "webp"] (real format from the bytes). |
minFileSizeKb, maxFileSizeMb | 0, 25 | File size limits. |
urlPattern, excludeUrlPattern | – | Regex on the image URL, e.g. /products/ or logo|icon|sprite. |
sameDomainOnly | false | Skip images hosted on other sites (ads, trackers); the site's own CDN subdomains count. |
upgradeToOriginals | true | Full-size originals instead of CDN thumbnails (falls back to the page's copy). |
srcset | largest | largest, all sizes, or none. |
includeLinkedImages, includeCssBackgrounds, includeMetaImages | true | Where to look. |
includeIcons, includeDataUris | false | Favicons/touch icons; inline data: images. |
preferOriginalFormat | true | Ask CDNs for the original JPEG/PNG instead of WebP/AVIF copies. |
dedupe, skipTrackingPixels | true | Remove duplicates; skip 1×1 pixels. |
fileNaming | original | 0001-original-name.jpg, alt, index or hash. |
zipPartSizeMb | 1000 | Split big ZIPs into parts. |
maxImagesPerPage, maxImagesTotal | 500, 100000 | Safety caps. |
proxyConfiguration, retryWithProxy | none, true | Blocked requests (403/429/503) are retried once through Apify Proxy. |
monitor, monitorKey | false | Only images that are new since the last monitor run. |
Output
- Dataset: one
imagerow per delivered image (fields above). Pages that failed or had no images get a freepage-errorrow with the reason (HTTP 403, "the page may build its content with JavaScript", …). - Key-value store:
images.zip(orimages-part-2.zip…, or one ZIP per page, or the individual files), andOUTPUTwith the ZIP links and per-page counts. The dataset'szipUrl/fileUrllinks work without a token.
Monitor mode: new images only
Tick monitor and schedule the run: Picpail remembers every image it has delivered for this URL list (by content
hash) and returns only images that are new since the last monitor run, such as new products in a category, new photos in a
gallery, or a changed homepage banner. Images you already have are skipped and not charged, so a daily check of a
quiet page costs nothing. Use monitorKey to keep the history when you edit the URL list.
Pricing
- $0.0005 per image delivered (event
image-downloaded): downloaded, verified as a real image, measured and saved. 1,000 images = $0.50. - Very large files only: $0.0001 per started MB above 2 MB of one file (event
large-image-megabyte), so a 5.5 MB photo costs $0.0009. Typical web images are well under 2 MB. LowermaxFileSizeMbor switch offupgradeToOriginalsto avoid it. - Free: duplicates, images skipped by your filters, links that turn out to be HTML pages, failed downloads, failed pages, and in monitor mode images you already received.
Set a maximum charge per run in Apify and Picpail stops cleanly when it's reached.
Run it on a schedule
Apify Console → Schedules → Create new → cron 0 7 * * * (daily) → Add Actor → Picpail with your pages
and "monitor": true. Through the API:
POST https://api.apify.com/v2/schedules?token=YOUR_TOKEN{"name": "picpail-new-product-photos","cronExpression": "0 7 * * *","timezone": "America/New_York","isEnabled": true,"actions": [{"type": "RUN_ACTOR","actorId": "cybermax/bulk-image-downloader","runInput": {"body": "{\"urls\":[\"https://www.example-shop.com/collections/new\"],\"minWidth\":400,\"monitor\":true,\"monitorKey\":\"new-arrivals\"}","contentType": "application/json"}}]}
Add an email, Slack or webhook notification on "Run succeeded" under the Actor's Integrations tab.
Integrations
API (synchronous): POST https://api.apify.com/v2/acts/cybermax~bulk-image-downloader/run-sync-get-dataset-items?token=YOUR_TOKEN
with the input JSON returns the image rows (each with zipUrl or fileUrl). Use "output": "files" when each
image needs its own link (e.g. to import into a CMS or a Google Sheet with =IMAGE()).
Make / Zapier: Apify app → "Run an Actor" (cybermax/bulk-image-downloader, run synchronously) → "Get dataset
items" → map fileUrl, width, height, alt into Airtable, a CMS or cloud storage.
n8n: Apify node ("Run an Actor and get dataset"), or HTTP Request:
POST https://api.apify.com/v2/acts/cybermax~bulk-image-downloader/run-sync-get-dataset-items?token=YOUR_TOKEN{"urls": ["https://books.toscrape.com/"], "output": "files", "minWidth": 100}
Google Sheets:
=IMPORTDATA("https://api.apify.com/v2/acts/cybermax~bulk-image-downloader/runs/last/dataset/items?format=csv&fields=pageUrl,imageUrl,width,height,alt,fileUrl&token=YOUR_TOKEN")
Python (pip install apify-client):
from apify_client import ApifyClientclient = ApifyClient("YOUR_TOKEN")run = client.actor("cybermax/bulk-image-downloader").call(run_input={"urls": ["https://books.toscrape.com/"], "minWidth": 100})zip_url = client.key_value_store(run["defaultKeyValueStoreId"]).get_record("OUTPUT")["value"]["zips"][0]["url"]print(zip_url)
JavaScript (npm i apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('cybermax/bulk-image-downloader').call({ urls: ['https://books.toscrape.com/'], output: 'files' });const { items } = await client.dataset(run.defaultDatasetId).listItems();
AI agents (MCP): Picpail is a tool on Apify's MCP server, https://mcp.apify.com/?tools=cybermax/bulk-image-downloader
(Authorization: Bearer YOUR_TOKEN). Claude Desktop / Cursor config:
{ "mcpServers": { "picpail": { "url": "https://mcp.apify.com/?tools=cybermax/bulk-image-downloader","headers": { "Authorization": "Bearer YOUR_TOKEN" } } } }
Typical agent prompts: "Download every product photo from these 20 pages as a ZIP", "Which images on our blog have no alt text?", "Get the full-size images from this Shopify collection, at least 1000 px wide".
When NOT to use it
- Pages that build their content with JavaScript (infinite-scroll feeds, single-page apps). Picpail reads the
HTML the server sends; such pages come back with few images and a
page-errorrow saying so. Use a browser-based scraper for those. - Sites behind strong bot walls (Cloudflare challenge, DataDome), e.g. Etsy and Unsplash search pages returned
403/401 in our tests, even through Apify's datacenter proxy. Try
proxyConfigurationwith residential proxies (billed by Apify to your account). - Pages behind a login, and whole-site crawls: Picpail downloads the pages you list; it doesn't follow links to other pages.
- Images you have no right to reuse. Downloading is not a licence: product photos, stock photos and artwork belong to their owners. Use the files for analysis, backups of your own sites, or with permission.
- Permanent hosting. ZIPs and files stay in the run's storage for your Apify plan's retention period (7 days on the free plan). Copy them somewhere permanent.
FAQ
Why is my ZIP bigger than the page? Full-size originals are much larger than the thumbnails a page shows (a
Shopify product photo is often 2000–4000 px). Switch off upgradeToOriginals to get the page's own copies.
Why is a .jpg link a WebP file? It won't be by default: preferOriginalFormat asks CDNs for the original
format, and each file's extension always matches its real format (format field).
How big can a job be? Images are written to disk one by one and ZIPs are split into parts, so memory stays
flat (a 295 MB, 155-image test run peaked under 600 MB). For very large jobs raise the run's memory (disk grows with it) or use zipPerPage.
Also from CyberMax
- Printwren: save the same pages as PDFs.
- SnapScout: a screenshot and the text of each page.
- Logolark: the company logo and icon for each domain.
- Inkpluck: the article text of blog and news pages.
All tools: Boardroom Buys · DomainDNA · HireHeat · Swellmeter · Hollerdex · Gripeline · Keyfern
Changelog
- 2026-09-24: First release: ZIP/files/list output, full-size originals for 9 CDN families, lazy-load and CSS images, real format/size per file, content dedupe, filters, monitor mode.
© 2026 CyberMax. All rights reserved.