Bulk Image Downloader: Download Images from a URL List to ZIP avatar

Bulk Image Downloader: Download Images from a URL List to ZIP

Pricing

from $1.00 / 1,000 image downloadeds

Go to Apify Store
Bulk Image Downloader: Download Images from a URL List to ZIP

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

Atesen Software

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

2 days ago

Last modified

Features

Limited permissions

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:image share images) as ZIP files for a hand-over or a migration.

Quick start

  1. Open the Input tab and paste image URLs into Image URLs, one per line. The prefilled input has three sample images.
  2. 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.
  3. Turn on Also create a ZIP archive to get images-part-001.zip in the key-value store as well.

Input

FieldWhat it does
imageUrlsDirect links to image files, one per line. Up to 10,000 per run. Only public links that open without a login work.
pageUrlsOptional. Public web pages to scan for images. Up to 200 per run.
maxImagesPerPageImages taken from each page, in page order. Default 50, maximum 500.
outputFormatoriginal (default), jpeg, png or webp.
maxWidth / maxHeightShrink larger images, aspect ratio kept. 0 = no limit. Images are never enlarged.
qualityJPG and WebP quality, 1 to 100. Default 85.
dedupeexact (default, SHA-256), perceptual (also near-duplicates) or none.
perceptualThresholdPerceptual mode only: how many of the 64 hash bits may differ, 0 to 20. Default 5.
fileNameTemplateDefault {index}-{name}. Placeholders: {index}, {name}, {hash}, {host}. The extension is added for you.
createZip / zipPartMaxMbAlso pack the saved images into ZIP parts of at most this size (default 250 MB).
maxImages, maxImageSizeMb, maxTotalSizeMbRun limits: images per run (default 1,000), size per image (default 25 MB), total size (default 2,000 MB).
downloadTimeoutSecs / maxConcurrencyTimeout 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> src and srcset (largest size), lazy-load data-src, <picture> sources, og:image, twitter:image and <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. exact skips byte-identical files. perceptual also skips the same picture at another size or compression level. Each duplicate row points to the first copy in duplicateOf and is not charged.
  • Packs images into images-part-001.zip, images-part-002.zip and 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) or no-images for 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 failed row, and maxConcurrency can 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 failed row; 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 http and https addresses 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 fileUrl links 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.