# Bulk Image Downloader - Download All Images from URLs + ZIP (`kadi_bence/bulk-image-downloader`) Actor

Download all images (JPG, PNG, WebP, SVG, GIF, AVIF) or files like PDFs from web pages or direct links into a ZIP and key-value store. Input: URLs; optional file types, minimum size, crawl depth. Returns per file: download URL, type, width, height, bytes, alt text, source page. Default: 20 files.

- **URL**: https://apify.com/kadi_bence/bulk-image-downloader.md
- **Developed by:** [Bence Kadi](https://apify.com/kadi_bence) (community)
- **Categories:** Automation, SEO tools, E-commerce
- **Stats:** 5 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 files

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bulk Image Downloader: download all images from URLs + ZIP

Download **all images from any list of web pages**, or a list of **direct image/file links**, into **one ZIP file** and the run's key-value store. Every file gets a **public link** and a dataset row with its size, width × height, type, alt text and SHA-256. You pay **$0.80 per 1,000 files saved**, and **failures are free**.

### 🖼️ What is Bulk Image Downloader?

It reads the HTML of your pages (no browser, so it is fast and cheap), finds every image or file, checks its real type from its bytes and saves it. It also handles **PDFs, Word/Excel/PowerPoint, CSV, ZIP, MP3, MP4** and more.

- **Finds the images other tools miss:** the **largest `srcset`/`<picture>` version**, **lazy-loaded images** (`data-src`, `data-srcset`, `data-lazy-src`, `data-original` and 9 more), `<noscript>`, `og:image`, **CSS backgrounds**, video posters, JSON-LD images and file links. Placeholders and 1x1 tracking pixels are ignored.
- **Real file checks:** an "image" that is really an HTML error or hotlink-protection page is caught and not charged. Width and height are read for JPG, PNG, WebP, GIF, AVIF, SVG, BMP, ICO, TIFF and HEIC.
- **Filters and dedupe:** type, min width/height, min/max size; identical content (SHA-256) is skipped for free.

**Use cases:** Developer tools (process & convert media, transform & process data) · Collect & distribute content.

#### Use cases

- **E-commerce teams:** download supplier or shop product photos for migration or marketplace listings.
- **AI and RAG pipelines:** collect openly licensed images with alt text, dimensions and SHA-256.
- **Agencies:** back up every image and PDF of an old site before a redesign.
- **Research and archiving:** save the reports (PDF) and documents linked from public pages.
- **URL list to ZIP:** paste thousands of direct links from a spreadsheet and get one archive back.
- **Developers:** call it from Make, Zapier, n8n, the API or an AI agent (MCP) and use each file's `publicUrl`.

#### Output fields

One dataset row per file. All fields:

| Field | Description | Example |
|---|---|---|
| `sourcePage` | Page where the file was found. `null` for direct links from your input | `https://commons.wikimedia.org/wiki/Category:Quality_images_of_cats` |
| `fileUrl` | Original URL of the file | `https://upload.wikimedia.org/.../Chartreux-cat-edouard-marie.jpg` |
| `discoveredBy` | Where it was found: `input`, `img`, `srcset`, `picture`, `lazy`, `noscript`, `meta`, `css`, `media`, `jsonld`, `link` (or `page` for a failed page row) | `srcset` |
| `altText` | The image's alt text, when the page has one | `null` |
| `status` | `stored`, `failed`, `blocked`, and for skipped rows `filtered` or `duplicate` | `stored` |
| `storedKey` | Key of the file in the key-value store (also its name inside the ZIP) | `00005-Chartreux-cat-edouard-marie.jpg` |
| `publicUrl` | Public download link of the file | `https://api.apify.com/v2/key-value-stores/<store-id>/records/...` |
| `zipKey` | Which ZIP part contains the file | `files.zip` |
| `fileType` | Real type, detected from the file's bytes | `jpg` |
| `contentType` | MIME type | `image/jpeg` |
| `bytes` | File size in bytes | `1760428` |
| `width` | Image width in pixels (`null` if not an image or unreadable) | `2400` |
| `height` | Image height in pixels | `1714` |
| `sha256` | SHA-256 checksum of the file content | `793c03f7cb71...` |
| `duplicateOf` | For skipped duplicates: URL of the first copy | `null` |
| `httpStatus` | HTTP status of the download | `200` |
| `error` | Why the file failed or was skipped (`null` when stored) | `HTTP 404` |
| `downloadedAt` | When the file was saved (UTC) | `2026-10-05T07:02:16.349Z` |

### 🚀 How to use Bulk Image Downloader

1. Open [Bulk Image Downloader](https://apify.com/kadi_bence/bulk-image-downloader) in Apify Store and click **Try for free** (or **Start**).
2. Paste your **URLs**, one per line: web pages (`https://example.com/gallery`) and/or direct file links (`https://example.com/photo.jpg`, `.../report.pdf`).
3. Pick the **file types** (default: JPG, PNG, WebP, GIF, SVG, AVIF). Optionally set **min width** (e.g. 150 px skips icons) and **max files**.
4. Click **Start**. The prefilled example (30 freely licensed images from 2 Wikimedia Commons pages) takes about 15 seconds.
5. Download your results: the **ZIP archive** link in the Output tab downloads everything at once. The **Files** tab shows previews and links, and you can export the table as JSON, CSV, Excel and more.

### 🔧 Input guide

#### URLs (`urls`)

Web pages and/or direct file links, one per line (`example.com` works too). Up to 5,000 per run; unusable lines are skipped and listed in `invalidInputs` in the run summary.

- **Good:** a gallery page with images in its HTML (`https://commons.wikimedia.org/wiki/Category:Quality_images_of_cats`), or a direct link (`https://example.com/report.pdf`).
- **Bad:** a gallery built by JavaScript (infinite scroll, some single-page apps): those images are not in the HTML. Collect their URLs another way and paste them as direct links.
- **Direct file links are always downloaded, whatever their type.** Private and local addresses (localhost, 192.168.x, cloud metadata) are refused.

#### File types (`fileTypes`)

Which files found on pages to keep: jpg, png, webp, gif, svg, avif, bmp, ico, tiff, heic, pdf, doc(x), xls(x), ppt(x), odt, ods, rtf, epub, csv, txt, json, xml, zip, gz, 7z, rar, mp3, wav, ogg, m4a, mp4, webm, mov. A file whose real type (from its bytes) is not selected is skipped for free. **Tip:** for all PDFs of a website, select only `pdf` with crawl depth 1.

#### Limits and filters

- `maxFiles` (default 100, max 100,000): stop after this many saved files. Also a hard cap on the cost.
- `minWidth` / `minHeight` (px): **150** skips icons, spacers and tracking pixels. Images whose size can't be read are kept.
- `minFileSizeKb` / `maxFileSizeMb` (default 0 / 25, max 100 MB): the max is checked **before downloading** when the server reports the size, and again while streaming.
- `maxDepth`: `0` (default) = only your pages, `1` = also pages they link to **on the same website**, `2` = one level further. Direct file links are never crawled.
- `maxPagesPerStartUrl` (default 20, max 500): page cap per listed URL when crawling. **Warning:** depth 2 on a big site reaches many pages.

#### ZIP, storage and names

- `createZip` (on) packs every file into `files.zip`. `storeFiles` (on) also saves each file with a public link; turn it off if you only need the ZIP. At least one must be on.
- `zipMaxMb` (default 100, range 10-400): start a new ZIP part at this size. Parts need about 2x their size in memory.
- `dedupe` (on): skip identical content (SHA-256), even under another URL. Free.
- `fileNamePattern` (default `{index}-{name}`): tokens `{index}`, `{name}`, `{host}`, `{hash}`, `{page}`, `{type}`; must contain `{index}`, `{name}` or `{hash}`. The extension is added. Characters not allowed in keys (including non-ASCII) become `-`.

#### Other options

- `outputSkipped` (off): add free rows for skipped files (duplicates, filtered, robots.txt). Failed downloads are always listed.
- `maxConcurrency` (default 10, max 50): at most **6 per website**, and fewer on small memory.
- `proxyConfiguration`: optional Apify Proxy (datacenter). Residential proxies are refused.

**Always on:** robots.txt (including `Crawl-delay`, capped at 30 s). Requests time out after 30 s, one download after 5 minutes, and 408/425/429/5xx errors are retried up to 2 times.

#### Example input

```json
{
  "urls": [
    "https://commons.wikimedia.org/wiki/Category:Quality_images_of_cats",
    "https://commons.wikimedia.org/wiki/Category:Featured_pictures_of_landscapes"
  ],
  "fileTypes": ["jpg", "png", "webp", "gif", "svg", "avif"],
  "maxFiles": 30,
  "minWidth": 150,
  "maxDepth": 0,
  "createZip": true,
  "storeFiles": true,
  "dedupe": true,
  "fileNamePattern": "{index}-{name}"
}
```

### 📦 Output

#### Dataset row (real run on 2026-10-05)

This row is a direct link to a full-size Wikimedia Commons photo; the store ID in `publicUrl` is shortened:

```json
{
  "sourcePage": null,
  "fileUrl": "https://upload.wikimedia.org/wikipedia/commons/8/80/Chartreux-cat-edouard-marie.jpg",
  "discoveredBy": "input",
  "altText": null,
  "status": "stored",
  "storedKey": "00005-Chartreux-cat-edouard-marie.jpg",
  "publicUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/00005-Chartreux-cat-edouard-marie.jpg",
  "zipKey": "files.zip",
  "fileType": "jpg",
  "contentType": "image/jpeg",
  "bytes": 1760428,
  "width": 2400,
  "height": 1714,
  "sha256": "793c03f7cb71c5b3aa1bde84141fed124b2e3021dfc95998e07d2be4f7dc9281",
  "duplicateOf": null,
  "httpStatus": 200,
  "error": null,
  "downloadedAt": "2026-10-05T07:02:16.349Z"
}
```

Failed files get `status: "failed"` or `"blocked"` and an `error` such as `HTTP 404`, `Got a web page instead of a file (blocked hotlink or removed file?)` or `Domain not found (DNS lookup failed)`. They are not charged.

#### Dataset views

- **Files** (default): image preview, original URL, type, dimensions, bytes, alt text, source page, status, error.
- **Links and checksums**: store key, file link, ZIP part, MIME type, SHA-256, duplicate of, HTTP status, download time.

#### Key-value store files

- **Each file** under its `storedKey`, with a public link (when `storeFiles` is on).
- **`files.zip`**: all saved files, named like their keys. It is written to disk as files arrive; at `zipMaxMb` it is uploaded and `files-part-2.zip`, `files-part-3.zip`... follow. Already-compressed formats (JPG, PNG, MP4...) are stored as-is.
- **`RUN_SUMMARY`**: JSON report with pages scanned, files saved, MB, skipped and failed counts and the ZIP links. Real example (shortened):

```json
{
  "pagesScanned": 2,
  "filesFound": 228,
  "filesStored": 30,
  "filesFailed": 0,
  "skipped": { "dimensions": 5, "robotsTxt": 1 },
  "zipFiles": [{ "key": "files.zip", "files": 30, "bytes": 435399, "mb": 0.44 }],
  "chargeLimitReached": false,
  "durationSecs": 5.7
}
```

The Output tab links to both views, the ZIP and the run summary.

#### Export

Export the dataset as **JSON, CSV, Excel, XML, RSS or an HTML table** from the Storage tab, or fetch it with the Apify API. The ZIP is at `https://api.apify.com/v2/key-value-stores/<store-id>/records/files.zip`.

### 💵 Pricing: $0.80 per 1,000 files

- **`file` event: $0.0008 per saved file** ($0.80 per 1,000).
- **`large-file-mb` event: $0.0005** for each started MB above the first 2 MB of one file. A 5 MB photo = $0.0008 + 3 × $0.0005 = $0.0023. Typical web images are far below 2 MB and never pay it.
- Plus Apify's $0.00005 per-run start fee.
- **Free:** pages scanned, failed downloads, 404s, blocked pages, duplicates, filtered-out files and robots.txt-skipped files.

| Run | Files saved (under 2 MB each) | Cost |
|---|---|---|
| Prefilled example | 30 | $0.024 + $0.00005 |
| Product photos | 1,000 | $0.80 + $0.00005 |
| Thumbnails | 10,000 | $8.00 + $0.00005 |
| Largest run allowed | 100,000 | $80.00 + $0.00005 |

Set **Max charge per run** in the run options to cap spending: the run stops cleanly at your limit and never keeps a file it didn't charge for.

Why per file? Tools that charge per input URL cost $7-70 per 1,000 URLs, so 1,000 direct image links cost 10-90× more there.

### 🔌 Use it via API

**JavaScript** (`npm install apify-client`):

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('kadi_bence/bulk-image-downloader').call({
    urls: ['https://commons.wikimedia.org/wiki/Category:Quality_images_of_cats'],
    fileTypes: ['jpg', 'png', 'webp'],
    maxFiles: 50,
    minWidth: 150,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((i) => i.publicUrl));
```

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("kadi_bence/bulk-image-downloader").call(run_input={
    "urls": ["https://example.com/report.pdf", "https://example.com/photo.jpg"],
    "createZip": True,
    "storeFiles": False,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["fileUrl"], item["status"], item["zipKey"])
```

**cURL** (runs the Actor and returns the dataset rows):

```bash
curl -X POST "https://api.apify.com/v2/acts/kadi_bence~bulk-image-downloader/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://example.com/gallery"], "maxFiles": 20}'
```

**Apify CLI:**

```bash
apify call kadi_bence/bulk-image-downloader --input '{"urls": ["https://example.com/gallery"], "fileTypes": ["pdf"], "maxDepth": 1}'
```

**MCP for AI agents** (Claude, Cursor, VS Code and other MCP clients):

```json
{"mcpServers":{"apify":{"url":"https://mcp.apify.com/?actors=kadi_bence/bulk-image-downloader"}}}
```

### 🔗 Integrations & scheduling

- **Apify Schedules** (cron): back up a blog's images every Monday into a fresh ZIP.
- **Webhooks:** on "run succeeded", call your URL, then fetch `files.zip` from the run's key-value store.
- **Zapier / Make / n8n:** new sheet row with an image URL → run the Actor → write each `publicUrl` back.
- **Google Sheets, Slack, email:** export the Files table to a sheet, or post the ZIP link to Slack when a run finishes.

### 🧰 Related tools by the same developer

**Content pipelines**

- [Document to Markdown](https://apify.com/kadi_bence/document-to-markdown): PDF/Word/PowerPoint/Excel/OCR to Markdown and RAG chunks; $2 / 1,000 documents.

**Website due diligence**

- [Website Tech Stack Detector](https://apify.com/kadi_bence/tech-stack-detector): CMS, ecommerce, analytics, frameworks from 7,600+ fingerprints; $1.50 / 1,000 websites.
- [SEO Site Audit Crawler](https://apify.com/kadi_bence/seo-site-audit): broken links, redirects, titles/meta, canonical, hreflang on every page; $1.50 / 1,000 pages.
- [Website Screenshot & PDF API](https://apify.com/kadi_bence/website-screenshot): full-page/mobile PNG, JPEG, WebP and PDF captures; $2.50 / 1,000 screenshots.
- [Bulk WHOIS & RDAP Domain Lookup](https://apify.com/kadi_bence/domain-whois-lookup): registrar, age, expiry, DNS/MX/SPF/DMARC; $1.50 / 1,000 domains.

### ❓ FAQ

**How does it work?**
It loads each page's HTML (no browser), extracts image and file links, downloads the selected files, checks their real type and size, and saves them to the ZIP and key-value store.

**Am I allowed to download these images? Who owns the copyright?**
Downloading a file does not give you any rights to it. **Copyright stays with the owners of the images and files**, and you are responsible for having the right to download, store and reuse them: your own sites, openly licensed content such as Wikimedia Commons, or content you have permission for. Check the licence before you reuse anything. This is not legal advice. The Actor only downloads URLs you give it (and, with crawling on, pages on the same website). It always **respects robots.txt**, **never logs in**, and **does not bypass paywalls, CAPTCHAs or bot protection**; those downloads fail cleanly and are free. It doesn't extract personal data: it saves the files you asked for (and their alt text) into your own Apify storage.

**Why are some images on a page missing?**
Pages that load their gallery with JavaScript don't have the images in their HTML. Also check your **file types** and **min width/height** filters, and turn on **List skipped files too** to see what was skipped and why.

**What does "Blocked by the site's robots.txt" mean?**
The website asks automated tools not to fetch that page or file. We always follow it, and the file is free.

**Is it a full-size image or a thumbnail?**
From each `<img>` it takes the largest version the page offers in `srcset`/`<picture>`. Sites that only link to the full-size image ("view original") are covered when that link points directly to an image file.

**How fast is it?**
Usually 5-10 files per second per website. Downloading from several sites at once is faster. In one test, 150 files (3.9 MB) took 18 seconds. Sites whose robots.txt sets a `Crawl-delay` (e.g. 4 seconds) are downloaded at that pace.

**How big can files and runs be?**
Files up to 100 MB each (default 25), up to 100,000 files per run. ZIP parts default to 100 MB (max 400 MB) and need about 2x their size in memory.

**What does a big job cost?**
Exactly the per-file price above; cap it with **Max files** and **Max charge per run**.

**Do I need a proxy?**
Usually not. Apify Proxy (datacenter) is available. Residential proxies are not supported.

**What if a run fails?**
Failed files are free and show the reason in `error`. If something looks wrong, open an issue in the **Issues** tab with the run link. Changes are listed in the changelog below.

### 📝 Changelog

- **2026-10-05:** Store page rewritten.
- **1.0 (2026-10-05):** First release.
  - Images and 36 file types from pages or direct links
  - lazy-load/srcset/picture/CSS/og:image discovery and an optional same-site crawl
  - type check from bytes, dimensions, SHA-256 dedupe
  - ZIP with parts and per-file public links
  - robots.txt always on, private-network (SSRF) protection, failed files not charged

### 🤝 Need a custom version?

I build custom scrapers, scheduled data feeds and integrations (CSV, Excel, Google Sheets, API, MCP for AI agents). Tell me the sites and fields you need:

- Email: bence.kadi@gmail.com
- Apify profile: https://apify.com/kadi_bence

### Related Actors

More low-cost Actors by the same developer, built on official APIs and public data:

- [Website Screenshot & PDF API](https://apify.com/kadi_bence/website-screenshot) — full-page screenshots and PDFs of any URL
- [Document to Markdown](https://apify.com/kadi_bence/document-to-markdown) — PDF, Word, PowerPoint and Excel to clean Markdown, with OCR
- [SEO Site Audit](https://apify.com/kadi_bence/seo-site-audit) — 0-100 SEO score per page, broken links and fix hints
- [Apple App Store Scraper](https://apify.com/kadi_bence/app-store-scraper) — top charts, app details, developers and reviews
- [PageSpeed Insights Bulk Checker](https://apify.com/kadi_bence/pagespeed-checker) — Core Web Vitals and Lighthouse scores in bulk
- [Website Tech Stack Detector](https://apify.com/kadi_bence/tech-stack-detector) — CMS, ecommerce, analytics and frameworks of any website
- [Bulk WHOIS & RDAP Domain Lookup](https://apify.com/kadi_bence/domain-whois-lookup) — registrar, dates and DNS for many domains

All my Actors: [apify.com/kadi_bence](https://apify.com/kadi_bence)

# Actor input Schema

## `urls` (type: `array`):

Web pages to download images/files from, and/or direct file links, one per line. Example: https://example.com/gallery or https://example.com/report.pdf. Pages are scanned for <img>, srcset, <picture>, lazy-loaded images, og:image, CSS backgrounds and links to files. Direct file links are always downloaded, whatever their type. Pages that load images with JavaScript are not supported. Only download files you have the right to use.

## `fileTypes` (type: `array`):

Which files found on the pages to keep. The real type is checked from the file's bytes, not just its name. Default: common image formats. Example: choose only PDF to get every PDF linked from a page.

## `minWidth` (type: `integer`):

Skip images narrower than this. Example: 150 skips icons, spacers and tracking pixels. 0 = no limit. Images whose size can't be read are kept. Skipped files are free.

## `minHeight` (type: `integer`):

Skip images shorter than this. Example: 150. 0 = no limit.

## `minFileSizeKb` (type: `integer`):

Skip files smaller than this. Example: 10. 0 = no limit.

## `maxFileSizeMb` (type: `integer`):

Skip files larger than this (checked before downloading when the server reports the size, and while downloading). Up to 100 MB.

## `createZip` (type: `boolean`):

Pack every saved file into files.zip in the key-value store (split into files-part-2.zip, files-part-3.zip... when it passes the ZIP size limit).

## `storeFiles` (type: `boolean`):

Save every file as its own key-value store record with a public link (publicUrl in the results). Turn off if you only need the ZIP. Keep at least one of this and Create ZIP on.

## `dedupe` (type: `boolean`):

Skip files whose content (SHA-256) was already saved in this run, even under a different URL. Duplicates are free.

## `fileNamePattern` (type: `string`):

Name of each saved file (key-value store key and name inside the ZIP). Tokens: {index} (00001...), {name} (original file name), {host}, {hash} (SHA-256 prefix), {page} (number of the start URL), {type}. Must contain {index}, {name} or {hash}. The extension is added automatically. Characters not allowed in keys become '-'. Example: {host}-{index}-{name}.

## `outputSkipped` (type: `boolean`):

Also add a (free) row for files that were skipped: duplicates, too small, wrong type, too large, blocked by robots.txt. Failed downloads are always listed.

## `maxFiles` (type: `integer`):

Stop after this many files are saved. You pay per saved file, so this also caps the cost. Default 20; example: 1000.

## `maxDepth` (type: `integer`):

0 = only the pages you list. 1 = also pages they link to on the same website. 2 = one level further. Direct file links are never crawled.

## `maxPagesPerStartUrl` (type: `integer`):

With a crawl depth above 0: at most this many pages are scanned per URL you listed (including that page). Example: 50.

## `zipMaxMb` (type: `integer`):

Start a new ZIP part when the current one reaches this size. Larger parts need more run memory (about 2x the part size). Example: 100.

## `maxConcurrency` (type: `integer`):

How many files to download at the same time (at most 6 per website, and fewer when the run's memory is small). Example: 10.

## `proxyConfiguration` (type: `object`):

Usually not needed. Use Apify Proxy (datacenter) to download from other IP addresses. Residential proxies are not supported. This Actor does not bypass logins, paywalls or bot protection.

## Actor input object example

```json
{
  "urls": [
    "https://commons.wikimedia.org/wiki/Category:Quality_images_of_cats",
    "https://commons.wikimedia.org/wiki/Category:Featured_pictures_of_landscapes"
  ],
  "fileTypes": [
    "jpg",
    "png",
    "webp",
    "gif",
    "svg",
    "avif"
  ],
  "minWidth": 150,
  "minHeight": 0,
  "minFileSizeKb": 0,
  "maxFileSizeMb": 25,
  "createZip": true,
  "storeFiles": true,
  "dedupe": true,
  "fileNamePattern": "{index}-{name}",
  "outputSkipped": false,
  "maxFiles": 30,
  "maxDepth": 0,
  "maxPagesPerStartUrl": 5,
  "zipMaxMb": 100,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `files` (type: `string`):

Every saved file with preview, original URL, type, dimensions, size and alt text.

## `zip` (type: `string`):

All saved files in one ZIP (big runs add files-part-2.zip, ... - see the run summary).

## `details` (type: `string`):

Key-value store keys, public links, ZIP part, MIME type and SHA-256 per file.

## `summary` (type: `string`):

Pages scanned, files saved, MB, skipped/failed counts and ZIP links.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://commons.wikimedia.org/wiki/Category:Quality_images_of_cats",
        "https://commons.wikimedia.org/wiki/Category:Featured_pictures_of_landscapes"
    ],
    "fileTypes": [
        "jpg",
        "png",
        "webp",
        "gif",
        "svg",
        "avif"
    ],
    "minWidth": 150,
    "maxFiles": 30,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kadi_bence/bulk-image-downloader").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urls": [
        "https://commons.wikimedia.org/wiki/Category:Quality_images_of_cats",
        "https://commons.wikimedia.org/wiki/Category:Featured_pictures_of_landscapes",
    ],
    "fileTypes": [
        "jpg",
        "png",
        "webp",
        "gif",
        "svg",
        "avif",
    ],
    "minWidth": 150,
    "maxFiles": 30,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("kadi_bence/bulk-image-downloader").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://commons.wikimedia.org/wiki/Category:Quality_images_of_cats",
    "https://commons.wikimedia.org/wiki/Category:Featured_pictures_of_landscapes"
  ],
  "fileTypes": [
    "jpg",
    "png",
    "webp",
    "gif",
    "svg",
    "avif"
  ],
  "minWidth": 150,
  "maxFiles": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call kadi_bence/bulk-image-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kadi_bence/bulk-image-downloader"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Ouf0RIHIDsbw2RRQQ/builds/nD38T4ArRLZftfmv8/openapi.json
