Bulk Image Downloader avatar

Bulk Image Downloader

Pricing

Pay per usage

Go to Apify Store
Bulk Image Downloader

Bulk Image Downloader

Download every image from a list of public web pages or direct image URLs, with size and type filters, optional ZIP output and per-image links in the dataset.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Cole Cassel

Cole Cassel

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Give it a list of web pages, or direct image links, and it finds and downloads every image. Each one gets a direct download link, and you also get a single ZIP file of everything. It looks well beyond <img> tags:

  • responsive srcset and <picture> sources (it keeps the largest version);
  • lazy-load attributes such as data-src;
  • Open Graph and Twitter preview images;
  • CSS background images.

Duplicates, tiny icons and unwanted formats are filtered out automatically.

You pay $0.003 per page plus $0.0005 per saved image. That comes to $0.013 for a page with 20 images, compared with $0.07 per page for the most-used alternative.

What it does

  • Fetches each start URL. If the URL is an HTML page, it extracts image URLs from:
    • <img src>, lazy attributes (data-src, data-lazy-src, data-original, …), srcset and <picture><source>;
    • og:image, twitter:image and apple-touch-icon tags;
    • inline style="background-image:…" and <style> blocks;
    • optionally, <a href> links that point at image files.
  • If the URL is itself an image, it simply downloads it.
  • Checks the file's real type from its bytes, not the file name:
    • JPEG, PNG, GIF, WebP, AVIF, SVG, BMP or ICO;
    • measures width and height;
    • drops files smaller than minWidth×minHeight;
    • drops exact duplicates by SHA-1.
  • Stores every image in the run's key-value store and adds it to images.zip.
  • Returns one dataset row per image (type: "image") and one summary row per page (type: "page"), plus an OUTPUT record with totals and the ZIP link.
  • Is polite by default:
    • respects robots.txt;
    • waits between requests to the same host;
    • identifies itself (BulkImageDownloaderBot/1.0);
    • refuses private or internal network addresses.

Use cases

  • Collecting product or catalog photos from your own or a partner's public site.
  • Downloading open-licensed media, for example from Wikimedia Commons, for research and datasets.
  • Website migrations and backups: grab every image from a list of pages.
  • Building image datasets for AI or vision projects from public sources you are allowed to use.
  • Auditing a site's images: formats, sizes, missing alt text.

Input

{
"startUrls": [
{ "url": "https://commons.wikimedia.org/wiki/Commons:Featured_pictures/Animals/Birds" },
{ "url": "https://en.wikipedia.org/wiki/Bald_eagle" },
{ "url": "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png" }
],
"maxImagesPerPage": 20,
"maxTotalImages": 60,
"minWidth": 100,
"minHeight": 100,
"createZip": true
}
FieldDefaultNotes
maxImagesPerPage / maxTotalImages100 / 1000Hard caps, which also cap your cost
minWidth / minHeight50 pxRemoves icons and tracking pixels; SVGs have no pixel size and are kept
maxImageMb25Larger files are skipped
imageTypesallChoose any of jpeg, png, gif, webp, avif, svg, bmp, ico
includeSrcset, includeBackgroundImages, includeMetaImagestrueTurn sources off to get fewer, more focused images
includeLinksToImagesfalseAlso follow <a href="….jpg"> links
sameDomainOnlyfalseKeep only images hosted on the page's own site
urlIncludeRegex / urlExcludeRegex—Case-insensitive filters on image URLs
createZip / maxZipMbtrue / 100The ZIP stops growing at the cap; images stay in the store either way
respectRobotsTxttrue
maxConcurrency / minDelayBetweenRequestsSecs5 / 0.25 s
requestTimeoutSecs / maxRetries30 s / 2Retries with exponential backoff on timeouts and on 429/5xx

Output

Real rows from a test run on 2026-10-18. On Apify, fileUrl and zipUrl are public links.

An image row:

{
"type": "image",
"url": "https://thumb.wikimedia.org/wikipedia/commons/thumb/d/db/Bald_eagle_about_to_fly_in_Alaska_%282016%29.jpg/500px-Bald_eagle_about_to_fly_in_Alaska_%282016%29.jpg?utm_source=en.wikipedia.org&utm_campaign=parser&utm_content=thumbnail",
"ok": true,
"pageUrl": "https://en.wikipedia.org/wiki/Bald_eagle",
"foundIn": "srcset",
"alt": "",
"imageType": "jpeg",
"width": 500,
"height": 400,
"bytes": 41607,
"sha1": "cbc23b0ff7a6e3c7bbcc7e7504f8dc5416771b81",
"fileKey": "500px-Bald_eagle_about_to_fly_in_Alaska_(2016)-6ed4a69395.jpg",
"fileUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/500px-Bald_eagle_about_to_fly_in_Alaska_(2016)-6ed4a69395.jpg",
"attempts": 1,
"processedAt": "2026-10-18T19:09:38Z"
}

A page summary row. This page had 1,232 candidate images; 20 were saved because of maxImagesPerPage:

{
"type": "page",
"url": "https://commons.wikimedia.org/wiki/Commons:Featured_pictures/Animals/Birds",
"ok": true,
"finalUrl": "https://commons.wikimedia.org/wiki/Commons:Featured_pictures/Animals/Birds",
"imagesFound": 1232,
"imagesSaved": 20,
"imagesFailed": 0,
"imagesSkipped": { "max_images_per_page": 1158, "too_small": 54 },
"processedAt": "2026-10-18T19:10:02Z"
}

The OUTPUT record in the key-value store:

{
"imagesSaved": 45,
"pagesProcessed": 3,
"failures": 2,
"stoppedByBudget": false,
"zipUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/images.zip",
"zipImages": 45,
"zipTruncated": false
}

Failures become rows with ok: false and an error.code:

  • ROBOTS_DISALLOWED, HTTP_404 and other HTTP_<status> codes, TIMEOUT;
  • NETWORK_ERROR, DNS_ERROR, PRIVATE_ADDRESS, INVALID_URL;
  • TOO_LARGE, NOT_HTML_OR_IMAGE.

The test run handled 6 start URLs in 30 seconds:

  • 45 images saved (27 JPEG, 7 PNG, 6 WebP, 5 SVG);
  • a 1.6 MB ZIP;
  • one robots.txt block and one 404, both recorded as free error rows.

Pricing

Pay per event:

EventPrice
HTML page processed$0.003
Image saved$0.0005 ($0.50 per 1,000)
Run start (Apify standard)$0.00005 per GB of memory

Skipped images, failed downloads and failed pages are free. Direct image URLs cost only the image fee. Use maxTotalImages, or a maximum cost per run, to cap spending; the actor stops cleanly when either limit is reached.

Limits

  • Reads the HTML the server sends and does not run JavaScript. Images that only a script adds after load won't be found. For those pages, use a browser-based scraper first.
  • External CSS files aren't fetched; only inline and <style> backgrounds are found.
  • Duplicates are detected by exact file content. The same photo at two sizes, such as a 250 px and a 500 px thumbnail, counts as two images.
  • No logins, cookies or CAPTCHA solving.
  • You are responsible for having the right to use the images you download. Check each site's terms and the image licenses.

FAQ

Why did a page give me fewer images than I see in the browser? The likely causes:

  • the images are added by JavaScript;
  • they are smaller than minWidth/minHeight;
  • they are duplicates;
  • you hit maxImagesPerPage.

The page row's imagesSkipped shows the counts for each reason.

Does it get the full-resolution image? For srcset and <picture> it picks the largest candidate the page offers. It does not guess hidden original URLs.

Can I only get JPEGs from one site? Yes. Set imageTypes: ["jpeg"] and sameDomainOnly: true, or use urlIncludeRegex.

Where is the ZIP? The zipUrl in the OUTPUT record, which is also linked on the run's Storage tab.