# Image Resizer – Bulk Resize Images & Crop Images (`tidyrun/image-resizer`) Actor

Resize images in bulk to every size you need in one run: thumbnails, web sizes, exact crops or padded squares. Keep the format or convert to WebP, get one ZIP, and see the exact dimensions of every file. Failed images are free.

- **URL**: https://apify.com/tidyrun/image-resizer.md
- **Developed by:** [Tidyrun](https://apify.com/tidyrun) (community)
- **Categories:** Developer tools, E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 resized images

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

## Image Resizer – Bulk Resize to Many Sizes

Give it image links and the sizes you need. Every image comes back in **all of them in one run** — thumbnail, web size, exact square crop, padded social banner — each file named after its size, with the exact dimensions you actually got.

### Quick start

1. Paste your image links into **Image URLs** (or upload a text file with one URL per line).
2. Leave the **Sizes** as they are, or write your own — one per line.
3. Click **Start**. The **Output** tab shows every file with its size name and dimensions.

Input example:

```json
{
  "imageUrls": [
    { "url": "https://example.com/photo.jpg" },
    { "url": "https://example.com/logo.png" }
  ],
  "sizes": ["thumb:400x400 crop", "medium:800", "og:1200x630 pad", "large:1600"],
  "format": "webp",
  "zip": true
}
```

Output row (shortened):

```json
{
  "sourceUrl": "https://example.com/photo.jpg",
  "size": "thumb",
  "requested": "thumb:400x400 crop",
  "status": "resized",
  "fileUrl": "https://api.apify.com/v2/key-value-stores/.../photo-3f1c2a9b7e-thumb.webp",
  "width": 400,
  "height": 400,
  "bytes": 29307,
  "originalWidth": 1280,
  "originalHeight": 1709,
  "format": "webp",
  "cropped": true,
  "upscaled": false,
  "chargedAsImages": 1
}
```

### How to write a size

| You write | You get |
| --- | --- |
| `800` | At most 800 px wide, height follows the picture |
| `x600` | At most 600 px tall, width follows the picture |
| `800x600` | Fits inside 800 × 600 — nothing cut off, so one side is usually smaller |
| `800x600 crop` | Exactly 800 × 600, cut from the middle |
| `800x600 smart` | Exactly 800 × 600, cut around the busiest part of the picture |
| `1200x630 pad` | Exactly 1200 × 630, the gaps filled with your **Padding colour** |
| `thumb:400x400 crop` | The same, and the file is named `…-thumb.jpg` |

### Run it after a scraper

On your scraper or its task, open **Integrations**, search for this Actor and set its input:

```json
{
  "datasetId": "{{resource.defaultDatasetId}}",
  "urlField": "images.url"
}
```

Every time the scraper finishes, its images go through this Actor. Leave **URL field** empty and it finds the image links itself; use a dot path (`images.0.url`, `images.url` for a whole list) when you want one exact field. Each row keeps `recordIndexes`, the dataset rows the image came from.

### Settings worth knowing

| Setting | What it does |
| --- | --- |
| **Output format** | Keep the original, or convert everything to WebP, JPEG, PNG or AVIF as it is resized. |
| **Quality** | 82 by default, for JPEG, WebP and AVIF. PNG and GIF stay lossless. |
| **Enlarge images that are too small** | Off by default. A small source is returned at its own size rather than blown up, and the row says `upscaled: false`. |
| **Padding colour** | Only for `pad` sizes. `#ffffff`, `#0000` for transparent, or a name like `white`. |
| **Put everything in one ZIP** | One file to download instead of clicking through a list. |
| **Max file size** | Skip source images bigger than this instead of spending the run on them. |

### Why this one

| Common problem | What happens here |
| --- | --- |
| One run per size, so four runs for four sizes | Write all the sizes once; every image is made in all of them in a single run. |
| Files all called `output-1.jpg` | Each file is named after the source and the size, e.g. `photo-3f1c2a9b7e-thumb.jpg`. |
| "Is this really 400 × 400?" | Every row carries the dimensions you got, the original dimensions, and whether it was cropped or enlarged. |
| Small images come back blurry and stretched | Nothing is enlarged unless you ask, and a crop bigger than the source keeps the shape instead of inventing pixels. |
| Transparency turns black | Alpha is kept, and `pad` can fill with `#0000` to stay transparent. |
| Animated GIFs lose their animation | Animated sources keep every frame. |
| Photos come out rotated | EXIF orientation is applied before resizing. |
| "Out of memory" on big batches | Images are resized a few at a time within the run's memory, and one too large gets a clear error instead of crashing the run. |
| One site gets hammered and blocks you | At most 4 images at a time per site, with an automatic slow-down if a site rate-limits. |
| Paying for broken links | 404s, pages that are not images and oversized files are **never charged**. |

### Pricing

Pay per file produced. Files that fail are never charged, and there is no fee just for starting a run.

A resized file up to **3 megapixels** (about 2048 × 1448, which is larger than most things you resize *to*) counts as one — so a thumbnail from a 40-megapixel photo is still one. Only a file bigger than 3 megapixels counts one more per 3 megapixels. Each row says what it was charged as in `chargedAsImages`.

Four sizes of one image are four files, so one source image at four sizes counts as four.

### Call it from your code

```bash
curl -X POST "https://api.apify.com/v2/acts/tidyrun~image-resizer/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"imageUrls":[{"url":"https://example.com/photo.jpg"}],"sizes":["thumb:400x400 crop","large:1600"]}'
```

### Tips

- Building a responsive `srcset`? `400`, `800`, `1600` in one run gives you the three files and their exact widths for the `w` descriptors.
- Product grid? `thumb:400x400 crop` keeps every tile the same shape; `pad` with `#ffffff` if you would rather not cut the product.
- Social preview? `1200x630 pad` is the usual Open Graph size, and padding keeps the whole picture visible.
- Want them smaller as well as shorter? Set **Output format** to WebP — resizing and converting happen in the same pass.

### Responsible use

Downloads the image URLs you provide, as an ordinary visitor. It does not log in, does not solve CAPTCHAs and does not collect personal data. Only resize images you have the right to use.

# Actor input Schema

## `imageUrls` (type: `array`):

Direct links to the images you want resized (JPEG, PNG, WebP, GIF, AVIF, TIFF). You can also upload a text file with one URL per line.

## `sizes` (type: `array`):

One size per line — every image is made in all of them. Write <code>800</code> for a max width, <code>800x600</code> to fit inside a box, <code>x600</code> for a max height. Add <code>crop</code> for exactly that size cut from the middle, <code>smart</code> to cut around the busiest part, or <code>pad</code> to add a background instead of cutting. Put a name in front (<code>thumb:400x400 crop</code>) and it becomes part of the file name.

## `datasetId` (type: `string`):

Optional dataset, for example from a scraper run. Its image links are downloaded together with the URLs above, and each row keeps the dataset record index. When connected as an integration after a scraper, use {{resource.defaultDatasetId}}.

## `urlField` (type: `string`):

Field that holds the image link: a URL, a list of URLs, or objects with url/src. Dot paths work: images.0.url, or images.url for every image in a list. Leave empty to find image links automatically.

## `format` (type: `string`):

Keep the original format, or convert everything as it is resized. WebP is usually the smallest for the web.

## `quality` (type: `integer`):

For JPEG, WebP and AVIF. 82 is the sweet spot: photos look unchanged at a fraction of the weight. PNG and GIF are always lossless.

## `allowUpscale` (type: `boolean`):

Off by default, so a small image is never blown up into a blurry one — it is returned at its own size and the row says so.

## `background` (type: `string`):

Used only by <code>pad</code> sizes. A hex value like <code>#ffffff</code>, <code>#0000</code> for transparent, or a name like <code>white</code>.

## `zip` (type: `boolean`):

Also save all the resized files as a single ZIP you can download in one click.

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

Download each URL once, and save identical files (same SHA-256) once. Duplicate rows link to the first copy and are not charged.

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

Skip source images larger than this instead of spending the run on them.

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

How long to wait for one image to download.

## Actor input object example

```json
{
  "imageUrls": [
    {
      "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Cat_November_2010-1a.jpg/1280px-Cat_November_2010-1a.jpg"
    },
    {
      "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/1280px-The_Earth_seen_from_Apollo_17.jpg"
    }
  ],
  "sizes": [
    "thumb:400",
    "medium:800",
    "large:1600"
  ],
  "format": "keep",
  "quality": 82,
  "allowUpscale": false,
  "background": "#ffffff",
  "zip": false,
  "dedupe": true,
  "maxFileSizeMb": 25,
  "timeoutSecs": 30
}
```

# Actor output Schema

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

One row per produced file: fileUrl, size name, width and height, bytes, the original dimensions, and any error.

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

Source images, files produced, total megabytes and the reason for anything that failed.

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

Every resized file saved by this run, plus the ZIP if you asked for one.

# 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 = {
    "imageUrls": [
        {
            "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Cat_November_2010-1a.jpg/1280px-Cat_November_2010-1a.jpg"
        },
        {
            "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/1280px-The_Earth_seen_from_Apollo_17.jpg"
        }
    ],
    "sizes": [
        "thumb:400",
        "medium:800",
        "large:1600"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidyrun/image-resizer").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 = {
    "imageUrls": [
        { "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Cat_November_2010-1a.jpg/1280px-Cat_November_2010-1a.jpg" },
        { "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/1280px-The_Earth_seen_from_Apollo_17.jpg" },
    ],
    "sizes": [
        "thumb:400",
        "medium:800",
        "large:1600",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("tidyrun/image-resizer").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 '{
  "imageUrls": [
    {
      "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Cat_November_2010-1a.jpg/1280px-Cat_November_2010-1a.jpg"
    },
    {
      "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/1280px-The_Earth_seen_from_Apollo_17.jpg"
    }
  ],
  "sizes": [
    "thumb:400",
    "medium:800",
    "large:1600"
  ]
}' |
apify call tidyrun/image-resizer --silent --output-dataset

```

## MCP server setup

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

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/uSgckC937mrFHgFFJ/builds/wF1ug10hwEZctRybU/openapi.json
