# Bulk File Downloader: Download Files from URLs — Ferrywren (`cybermax/bulk-file-downloader`) Actor

Bulk file downloader: download files from a list of URLs, or every PDF, Word, Excel, CSV and ZIP linked on web pages, into one ZIP or separate links. Type checked from the bytes, duplicates removed, a row per file with size and SHA-256. $1.50 per 1,000 files.

- **URL**: https://apify.com/cybermax/bulk-file-downloader.md
- **Developed by:** [CyberMax](https://apify.com/cybermax) (community)
- **Categories:** Automation, Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## Ferrywren: Bulk File Downloader — Download Files from URLs to ZIP

#### Every file from your links or pages, checked, in one ZIP

Give it file links, or web pages that link to files; get one ZIP (or one download link per file) of every PDF, Word, Excel, PowerPoint, CSV, ZIP, image, audio or video file, with a row per file: type checked from its bytes, size and SHA-256. $0.0015 per file.

**[▶ Try it now with a prefilled input](https://apify.com/cybermax/bulk-file-downloader)** · $0.0015 per file, duplicates and skips free (1,000 files = $1.50) · Apify's free plan includes $5 of credit a month

**Built for:** analysts collecting reports and filings · ops teams archiving price lists, spec sheets and manuals · researchers building document sets · anyone with a spreadsheet column of file URLs

**Real output** (real run, 24 Oct 2026, input below: 5 files, one ZIP, 1 duplicate skipped free):

| From | File in the ZIP | Type | Bytes | Found in |
|---|---|---|---|---|
| irs.gov/forms-pubs/about-form-w-9 | 0001-iw9.pdf | pdf | 189,808 | link "Print version PDF" |
| irs.gov/forms-pubs/about-form-w-9 | 0002-p1281.pdf | pdf | 808,789 | link "Publication 1281, Backup Withholding…" |
| irs.gov/forms-pubs/about-form-w-9 | 0003-p5027.pdf | pdf | 93,363 | link "Publication 5027, Identity Theft…" |
| irs.gov/pub/irs-pdf/fw9.pdf | 0001-fw9.pdf | pdf | 140,815 | direct link (the page's copy was a duplicate: free) |
| gstatic.com/webp/gallery/1.webp | 0001-1.webp | webp | 30,320 | direct link |

```json
{"urls": ["https://www.irs.gov/forms-pubs/about-form-w-9", "https://www.irs.gov/pub/irs-pdf/fw9.pdf", "https://www.gstatic.com/webp/gallery/1.webp"]}
```

### Ready-made inputs (one click)

Paste one of these into the Input tab and press **Start**.

| Job | Input | Result |
|---|---|---|
| **First try** (3 URLs) | `{"urls": ["https://www.irs.gov/forms-pubs/about-form-w-9", "https://www.irs.gov/pub/irs-pdf/fw9.pdf", "https://www.gstatic.com/webp/gallery/1.webp"]}` | One ZIP with the form, its publications and an image; the duplicate is skipped free. |
| **All PDFs from one page** | `{"urls": ["https://www.irs.gov/forms-pubs/about-form-w-9"], "fileTypes": ["pdf"], "output": "zip"}` | Every PDF linked from the page, in one ZIP. |
| **A download link per file** | `{"urls": ["https://www.irs.gov/forms-pubs/about-form-w-9"], "fileTypes": ["documents"], "output": "files"}` | Each file gets its own link, ready for Make, Zapier or n8n. |

### Use cases

- **Download all PDFs from a website page:** annual reports, investor decks, government forms, product manuals, safety data sheets. Point Ferrywren at the page; it finds every document link (including `download.php?file=…` style links and embedded PDF viewers) and downloads them.
- **URL list to ZIP:** paste a column of file links from a spreadsheet or a scraper's output; get one tidy ZIP with original file names.
- **Media backup:** MP4, MP3, WAV and image files linked from your own pages, with sizes and hashes for an inventory.
- **New-file alerts:** monitor mode on a schedule returns only files that appeared since the last run (new filings, new price lists, new datasheets).
- **Feeding AI pipelines:** each file gets a public download link (`"output": "files"`) that a RAG loader, Make, Zapier or n8n step can pick up.

### Why Ferrywren

| | Ferrywren | Typical file downloader |
|---|---|---|
| Works from pages, not only direct links | Yes: finds file links, `<a download>`, `?file=` links, embedded PDFs, `<video>`/`<audio>` sources | Usually direct URLs only |
| Real file type | Checked from the file's own bytes (a "PDF" link that returns a login page is not delivered and not charged) | Trusts the URL or header |
| Duplicates | Removed by content (SHA-256), free | Rarely |
| Big files | Streamed to disk, ZIP parts split automatically; memory stays flat | Often buffered in memory |
| Price | $0.0015 per file; big files add $0.002 per 10 MB above the first 10 MB | Per file plus start fees |

### Input

| Field | What it does |
|---|---|
| `urls` | File links and/or web pages, one per line (required). |
| `fileTypes` | Optional filter: `pdf`, `docx`, `xlsx`, `csv`, `mp4` … or a group: `documents`, `images`, `video`, `audio`, `archives`. Empty = keep every direct link; pages are searched for documents and archives. |
| `output` | `zip` (one ZIP), `zipPerPage` (one ZIP per input URL) or `files` (a download link per file). |
| `sameDomainOnly`, `urlPattern`, `excludeUrlPattern` | Narrow which links on a page are followed. |
| `maxFileSizeMb`, `minFileSizeKb`, `maxFilesPerPage`, `maxFilesTotal` | Limits. Skipped files are free. |
| `monitor`, `monitorKey` | Only files never delivered before for this watchlist. |
| `proxyConfiguration` | Optional proxy for sites that block datacenter IPs. Blocked downloads are retried once through Apify Proxy automatically. |

### Output

One dataset row per delivered file: `fileUrl`, `downloadUrl` (the ZIP or the file's own link), `fileName`, `fileType`, `mimeType`, `bytes`, `sha256`, `inputUrl`, `linkText`, `source` (link, download-link, embed, media, direct). URLs that could not be read get a `url-error` row with the HTTP status (free). The run's `OUTPUT` record lists the ZIP parts and per-URL counts.

### Pricing

- **$0.0015 per file delivered** ($1.50 per 1,000).
- **$0.002 per started 10 MB above the first 10 MB** of one file (a 35 MB video = 3 blocks = $0.006 extra). PDFs, documents and spreadsheets are almost always under 10 MB.
- Free: duplicates, filtered files, links that turn out to be HTML pages, failed downloads, failed URLs.
- Set a maximum charge per run in Apify's run options and Ferrywren stops cleanly when it is reached.

### Run it on a schedule

Apify Console → **Schedules** → **Create new** → cron `0 7 * * 1` (Mondays) → **Add Actor** → Ferrywren with your pages and `"monitor": true`. Through the API:

```json
POST https://api.apify.com/v2/schedules?token=YOUR_TOKEN
{
  "name": "ferrywren-new-reports",
  "cronExpression": "0 7 * * 1",
  "timezone": "America/New_York",
  "isEnabled": true,
  "actions": [{
    "type": "RUN_ACTOR",
    "actorId": "cybermax/bulk-file-downloader",
    "runInput": {
      "body": "{\"urls\":[\"https://www.example.com/investors/reports\"],\"fileTypes\":[\"pdf\"],\"monitor\":true,\"monitorKey\":\"ir-reports\"}",
      "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-file-downloader/run-sync-get-dataset-items?token=YOUR_TOKEN` with the input JSON returns the file rows.

**Make / Zapier:** Apify app → "Run an Actor" (`cybermax/bulk-file-downloader`, run synchronously, `"output": "files"`) → "Get dataset items" → map `downloadUrl`, `fileName`, `fileType` into Google Drive, Dropbox, Airtable or your CMS.

**n8n:** Apify node ("Run an Actor and get dataset"), or HTTP Request:

```
POST https://api.apify.com/v2/acts/cybermax~bulk-file-downloader/run-sync-get-dataset-items?token=YOUR_TOKEN
{"urls": ["https://www.irs.gov/forms-pubs/about-form-w-9"], "fileTypes": ["pdf"], "output": "files"}
```

**Google Sheets:**

```
=IMPORTDATA("https://api.apify.com/v2/acts/cybermax~bulk-file-downloader/runs/last/dataset/items?format=csv&fields=fileUrl,fileType,bytes,downloadUrl&token=YOUR_TOKEN")
```

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

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("cybermax/bulk-file-downloader").call(run_input={"urls": ["https://www.irs.gov/forms-pubs/about-form-w-9"], "fileTypes": ["pdf"]})
print(client.key_value_store(run["defaultKeyValueStoreId"]).get_record("OUTPUT")["value"]["zips"])
```

**AI agents (MCP):** `https://mcp.apify.com/?tools=cybermax/bulk-file-downloader` (Authorization: `Bearer YOUR_TOKEN`). Typical prompts: "Download every PDF linked on these three investor pages as a ZIP", "Get these 40 CSV export links and give me one download link each".

### When NOT to use it

- **Files behind a login** or a paywall: Ferrywren only downloads what a visitor without an account can open.
- **Streaming platforms** (YouTube, TikTok, Spotify and similar): those are not files on a page, and their terms forbid downloading. Use direct file links you have the right to download.
- **Pages that build their links with JavaScript:** Ferrywren reads the HTML the server sends; such pages report "no links" (free).
- **Whole-site crawls:** it reads the pages you list and the files they link to; it doesn't follow links to other pages.

### FAQ

**Why not a browser extension or wget?** Fine for one page on your laptop. Ferrywren runs on a schedule without you, checks each file's real type, removes duplicates, splits big ZIPs, and hands every file a link your automations can use.

**Why not the file downloaders that only take direct links?** Most of the time you have a page, not a list of file URLs. Ferrywren does both in one run, and charges nothing for links that turn out to be HTML pages.

**Can an AI agent use it (MCP)?** Yes. Add `https://mcp.apify.com/?tools=cybermax/bulk-file-downloader` as an MCP server in Claude, Cursor, VS Code or any MCP client.

**How big can a file be?** Up to 3.8 GB per file (`maxFileSizeMb`). Files stream to disk, so memory stays flat; for very large videos raise the run's memory, which also raises its disk.

**How long are files kept?** In the run's storage for your Apify plan's retention period (7 days on the free plan). Copy them somewhere permanent.

**Is it legal to use?** Ferrywren downloads files that pages offer publicly, with no login. Files usually belong to their owners; get the rights before you reuse or republish them. This is general information, not legal advice.

### Start now

**[▶ Try Ferrywren with a prefilled input](https://apify.com/cybermax/bulk-file-downloader)** · $0.0015 per file, duplicates and skips free. Questions or a missing file type? Open an issue on the Store page and it gets answered the same day.

### Also from CyberMax

- [Picpail — bulk image downloader](https://apify.com/cybermax/bulk-image-downloader): every image on a page, as full-size originals, in one ZIP.
- [Inkpluck — article extractor](https://apify.com/cybermax/article-extract): the text of blog and news pages as Markdown.
- [Capturewren — website screenshot API](https://apify.com/cybermax/website-screenshot): a screenshot and the text of each page.

### Changelog

- 2026-10-24: First release: file links and pages, type detection from bytes, content dedupe, ZIP / ZIP per page / file links, streaming for big files, monitor mode.

© 2026 CyberMax. All rights reserved.

# Actor input Schema

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

One URL per line. A file link (…/report.pdf, a CSV export, an MP4) is downloaded as it is. A web page is searched for links to files (PDF, Word, Excel, PowerPoint, CSV, ZIP… or the types you pick below) and each one is downloaded. Mix both freely.

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

Optional, e.g. pdf, docx, xlsx, csv, mp4, or a group: documents, images, video, audio, archives. Empty = keep every file you link directly, and look for documents and archives on pages. The type is checked from the file's own bytes, not just its name.

## `output` (type: `string`):

ZIP parts are split at the size below. 'files' stores every file with its own public link (handy for Make, Zapier, n8n or a CMS import).

## `sameDomainOnly` (type: `boolean`):

Skip file links on a page that point to other sites (CDNs of the same company count as other sites).

## `urlPattern` (type: `string`):

e.g. annual|2026

## `excludeUrlPattern` (type: `string`):

e.g. draft|thumbnail

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

Bigger files are skipped (free). For large videos raise the run's memory too: more memory = more disk.

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

Skip tiny files (placeholders, error stubs).

## `maxFilesPerPage` (type: `integer`):

Cap on file links followed from one page (the first ones on the page are kept).

## `maxFilesTotal` (type: `integer`):

A hard cap on files delivered (and charged) in this run.

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

The same file (by content) is delivered once, even from different URLs. Duplicates are free.

## `fileNaming` (type: `string`):

How files are named inside the ZIP or store.

## `monitor` (type: `boolean`):

For scheduled runs over the same pages: return (and charge) only files never delivered before for this watchlist, e.g. new reports, new price lists, new filings.

## `monitorKey` (type: `string`):

Optional name for this watchlist's saved state, so you can edit the URL list without starting over.

## `includeUntypedDownloads` (type: `boolean`):

Links marked with the HTML download attribute are files even when the URL has no extension (e.g. /export?id=7).

## `zipPartSizeMb` (type: `integer`):

Big jobs are split into several ZIP parts of at most this size.

## `concurrency` (type: `integer`):

Files downloaded at the same time.

## `timeoutSecs` (type: `integer`):

Per download. Raise it for very large files on slow servers.

## `retryWithProxy` (type: `boolean`):

When a site answers 401/403/429, retry once through Apify Proxy (datacenter).

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

Optional. Residential proxies help with sites that block datacenter IPs (billed by Apify to your account).

## Actor input object example

```json
{
  "urls": [
    "https://www.irs.gov/forms-pubs/about-form-w-9",
    "https://www.gstatic.com/webp/gallery/1.webp"
  ],
  "fileTypes": [],
  "output": "zip",
  "sameDomainOnly": false,
  "maxFileSizeMb": 500,
  "minFileSizeKb": 0,
  "maxFilesPerPage": 200,
  "maxFilesTotal": 10000,
  "dedupe": true,
  "fileNaming": "original",
  "monitor": false,
  "includeUntypedDownloads": true,
  "zipPartSizeMb": 1000,
  "concurrency": 4,
  "timeoutSecs": 120,
  "retryWithProxy": true
}
```

# Actor output Schema

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

No description

## `results` (type: `string`):

No description

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

No description

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

No description

# 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://www.irs.gov/forms-pubs/about-form-w-9",
        "https://www.gstatic.com/webp/gallery/1.webp"
    ],
    "fileTypes": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("cybermax/bulk-file-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://www.irs.gov/forms-pubs/about-form-w-9",
        "https://www.gstatic.com/webp/gallery/1.webp",
    ],
    "fileTypes": [],
}

# Run the Actor and wait for it to finish
run = client.actor("cybermax/bulk-file-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://www.irs.gov/forms-pubs/about-form-w-9",
    "https://www.gstatic.com/webp/gallery/1.webp"
  ],
  "fileTypes": []
}' |
apify call cybermax/bulk-file-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cybermax/bulk-file-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/kmbpOW1hOeTOdaZ7Q/builds/tsJyrCPNL30bBSM9q/openapi.json
