Bulk Image Downloader: Download Images from a URL List to ZIP
Pricing
from $1.00 / 1,000 image downloadeds
Bulk Image Downloader: Download Images from a URL List to ZIP
Download images in bulk from a list of URLs or web pages. Every file is saved to storage with a numbered name, with an optional ZIP, duplicate removal, resizing and conversion to JPG, PNG or WebP. One result row per image.
Pricing
from $1.00 / 1,000 image downloadeds
Rating
0.0
(0)
Developer
Atesen Software
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Features
Share
Got a spreadsheet, product feed or CMS export full of image URLs and no good way to download them all? This Actor downloads images in bulk from a list of image URLs (or from the images on web pages), saves each one as a file with a clean numbered name, removes duplicates and can pack everything into a ZIP.
Resize and convert on the way to JPG, PNG or WebP. Every image gets one result row with its size, type, hash and a download link.
Who uses it
- E-commerce and marketplace teams download product photos from a feed or CSV, shrink them to a width limit and convert them to WebP or JPG for a store or a listing.
- Data and research teams clean an image set before labeling or training: exact duplicates and the same picture saved at another size or compression are dropped.
- Agencies and site owners archive the images of a list of pages (gallery images,
og:imageshare images) as ZIP files for a hand-over or a migration.
Quick start
- Open the Input tab and paste image URLs into Image URLs, one per line. The prefilled input has three sample images.
- Click Start. Each image is saved as a file in the run's key-value store, and the dataset gets one row per image. The Images view in the Output tab shows a preview of every file.
- Turn on Also create a ZIP archive to get
images-part-001.zipin the key-value store as well.
Input
| Field | What it does |
|---|---|
imageUrls | Direct links to image files, one per line. Up to 10,000 per run. Only public links that open without a login work. |
pageUrls | Optional. Public web pages to scan for images. Up to 200 per run. |
maxImagesPerPage | Images taken from each page, in page order. Default 50, maximum 500. |
outputFormat | original (default), jpeg, png or webp. |
maxWidth / maxHeight | Shrink larger images, aspect ratio kept. 0 = no limit. Images are never enlarged. |
quality | JPG and WebP quality, 1 to 100. Default 85. |
dedupe | exact (default, SHA-256), perceptual (also near-duplicates) or none. |
perceptualThreshold | Perceptual mode only: how many of the 64 hash bits may differ, 0 to 20. Default 5. |
fileNameTemplate | Default {index}-{name}. Placeholders: {index}, {name}, {hash}, {host}. The extension is added for you. |
createZip / zipPartMaxMb | Also pack the saved images into ZIP parts of at most this size (default 250 MB). |
maxImages, maxImageSizeMb, maxTotalSizeMb | Run limits: images per run (default 1,000), size per image (default 25 MB), total size (default 2,000 MB). |
downloadTimeoutSecs / maxConcurrency | Timeout per download (default 60 s) and parallel downloads (default 4, maximum 10). |
Example input and output
A real run: three direct image URLs, original format, exact duplicate check. All other fields stayed at their defaults.
{"imageUrls": ["https://upload.wikimedia.org/wikipedia/commons/a/a9/Example.jpg","https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png","https://upload.wikimedia.org/wikipedia/commons/8/8f/Example.gif"],"outputFormat": "original","dedupe": "exact","fileNameTemplate": "{index}-{name}","createZip": false}
First dataset row of that run (store ID and signature in fileUrl replaced by placeholders):
{"index": 1,"sourceUrl": "https://upload.wikimedia.org/wikipedia/commons/a/a9/Example.jpg","pageUrl": null,"finalUrl": "https://upload.wikimedia.org/wikipedia/commons/a/a9/Example.jpg","status": "downloaded","error": null,"contentType": "image/jpeg","originalContentType": "image/jpeg","width": 172,"height": 178,"bytes": 9022,"originalBytes": 9022,"sha256": "99bd915a3819b1fee3722328ae904dde5459e9b15d56abd98b903c770a2f582c","phash": null,"fileKey": "00001-Example.jpg","fileUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/00001-Example.jpg?signature=<signature>","zipPart": null,"duplicateOf": null}
To resize to 1,200 px wide, convert to WebP, drop near-duplicates and get a ZIP, change these fields:
{"outputFormat": "webp","maxWidth": 1200,"quality": 80,"dedupe": "perceptual","createZip": true}
The run's key-value store also holds SUMMARY (counts, total size, ZIP part links and why the run stopped) and the ZIP parts.
What it does and what it does not
- Downloads JPG, PNG, WebP, GIF, AVIF, TIFF, BMP and HEIF. The real type is detected from the file bytes, not from the URL.
- Page mode (optional) reads
<img>srcandsrcset(largest size), lazy-loaddata-src,<picture>sources,og:image,twitter:imageand<link rel="image_src">. The Actor checks robots.txt before it opens a listed page and its redirect destinations. - Resizes (EXIF rotation applied) and converts to JPG, PNG or WebP. An animated GIF stays animated when converted to WebP.
- Finds duplicates.
exactskips byte-identical files.perceptualalso skips the same picture at another size or compression level. Each duplicate row points to the first copy induplicateOfand is not charged. - Packs images into
images-part-001.zip,images-part-002.zipand so on. Parts are written to disk one file at a time and uploaded when full, so large jobs do not run out of memory. - Reports a status per URL:
downloaded,duplicate,failed(with the reason: HTTP 403 or 404, too large, not an image, blocked address, robots.txt) orno-imagesfor a page without images. - Does not log in. Images or pages that need an account, cookies or a paid plan are not supported.
- Does not run JavaScript. Images a page only loads with scripts (infinite scroll, client-side galleries) are not found in page mode; pass their direct URLs instead.
- Does not get around bot protection and has no proxy setting. Sites that answer 403 or 429 to automated downloads give a
failedrow, andmaxConcurrencycan be lowered for a site that answers 429. - Does not crawl whole sites. Page mode reads only the pages you list.
- Does not support SVG. An SVG gives an uncharged
failedrow; supply a raster image instead.
Limits and safety
- Up to 10,000 image URLs and 200 page URLs per run, a size limit per image (default 25 MB, maximum 100 MB), a download timeout, a total size limit per run and a 50 megapixel decoding limit (larger images are refused, not half-processed).
- Only public
httpandhttpsaddresses are fetched. Private, loopback, link-local and cloud-metadata addresses are blocked, including host names that resolve to them and redirects that lead to them. - The
fileUrllinks are unguessable, but anyone who has one can open the file. Keep them private if the images are. - You are responsible for having the right to download and use the images you request (copyright, licenses, site terms). The Actor only fetches the URLs you give it.
Run it from the API, n8n, Make or Zapier
API. One request starts the Actor, waits for it and returns one row per image as JSON, each with a fileUrl. Put the token in the Authorization header, never in a URL:
curl -X POST "https://api.apify.com/v2/acts/atesen-software~bulk-image-downloader/run-sync-get-dataset-items?timeout=120" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{ "imageUrls": ["https://upload.wikimedia.org/wikipedia/commons/a/a9/Example.jpg"], "outputFormat": "webp", "maxWidth": 1200 }'
The synchronous endpoint waits at most 300 seconds. For larger jobs start the run with POST https://api.apify.com/v2/acts/atesen-software~bulk-image-downloader/runs, wait for it (or use a webhook) and read the rows from https://api.apify.com/v2/datasets/<datasetId>/items. The run object has defaultKeyValueStoreId; with createZip on, download the archive from https://api.apify.com/v2/key-value-stores/<defaultKeyValueStoreId>/records/images-part-001.zip with the same Authorization header.
n8n. Use the Apify node (Run Actor and Get Dataset), or an HTTP Request node with method POST, the URL above, a Header Auth credential (Authorization: Bearer <your token>) and the JSON input as body. Apify n8n integration
Make. Use the Apify modules Run an Actor and Get Dataset Items, or the HTTP, Make a request module with the same URL, header and body. Apify Make integration
Zapier. Use the Apify app to run this Actor or a saved task, trigger a Zap when a run finishes and fetch the dataset items. Apify Zapier integration
FAQ
Does it download images from Google Images, Instagram or Pinterest? Only if you give direct public image file URLs. It does not search or log in to platforms.
Why is an image failed with HTTP 403? The site refuses automated downloads or requires a login. Nothing is charged for it.
What counts as a duplicate? In exact mode, the same downloaded bytes. In perceptual mode, also the same picture at a different size or compression level (threshold 0 to 20, default 5). Cropped or rotated copies are not matched.
Can I get one ZIP file? Yes. With createZip on, a job smaller than the part size (default 250 MB) is one ZIP file. Bigger jobs are split into several parts.
How do I limit the cost? Set Max images per run, or the maximum cost per run in the run options. The Actor stops cleanly when it is reached.
Pricing
Pay per event: you are charged for an image that was saved and delivered. Failed, blocked and duplicate rows are free. Current prices are on the Pricing tab.
Built by Atesen Software.