# Image Compressor & Resizer: Compress Images in Bulk (`data-done-right/image-compressor`) Actor

Compress images in bulk: an image compressor and resizer API for lists of image URLs. Shrink JPG, PNG, WebP and AVIF, resize to a max width or height, strip EXIF, and get signed download links with the exact bytes saved.

- **URL**: https://apify.com/data-done-right/image-compressor.md
- **Developed by:** [Data Done Right](https://apify.com/data-done-right) (community)
- **Categories:** Developer tools, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.36 / 1,000 image compresseds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Compressor & Resizer: Compress Images in Bulk

Use this **image compressor** to **compress images in bulk** from a list of URLs. Paste direct image links, pick a quality, an output format and a maximum size, and get a smaller file for every image with a signed download link and the exact bytes saved. It is also an **image resizer**: shrink to a maximum width or height (never enlarged), or crop or pad to an exact size. No browser, no login, no API key.

Pay only for images that actually got smaller. If a file cannot be made smaller, you get the original back, `reduced: false`, and no charge.

### What can this image compressor do

- **Compress JPG, PNG, WebP, AVIF and GIF.** Also reads BMP, TIFF and HEIC (iPhone photos). One dataset row per URL with the original and compressed size and `savedPercent`.
- **Convert while compressing.** Output `jpeg`, `webp`, `png` or `avif`, or keep each image's own format.
- **Resize images.** Set `maxWidth` and/or `maxHeight` to fit inside a box. Small images are never enlarged. Use `resizeMode` `cover` (crop to the exact size) or `contain` (pad to the exact size).
- **Strip metadata.** On by default: removes EXIF (camera model, GPS position) and other metadata. The EXIF orientation is applied to the pixels first, so photos are never turned sideways, and colors are converted to sRGB before the color profile is dropped.
- **Smarter PNG.** Lossless re-compression plus an optional 256-color palette (keeps transparency) when it is smaller. Turn on `lossless` to never reduce colors.
- **Progressive JPEG** (on by default), lossless WebP and AVIF when you ask for it.
- **Safe with odd files.** CMYK becomes RGB, transparency is replaced by white (or your color) when saving as JPEG, animated GIF and WebP keep their animation, and huge images (over 64 megapixels) are refused before they are decoded.
- **Bulk and API-friendly.** Up to 5,000 images per run, optional dataset input (the output of another Actor), one bad URL never stops the run.

### How to compress images in bulk

1. Paste direct image links in **Image URLs** (one per line), or pick a dataset that contains image URLs.
2. Choose the **Output format** (try `webp`), a **Quality** (75-85 is a good start) and, if you want, a **Max width**.
3. Run it. Each compressed file is stored in the run's key-value store. The dataset has a signed `url` for it that works without an API token.

### How to resize images in bulk

Set `maxWidth` (and/or `maxHeight`). With `resizeMode: "fit"` every image is scaled down to fit inside the box and keeps its shape. For thumbnails of exactly the same size use `resizeMode: "cover"` (crop from the center) or `"contain"` (add a background color), with both `maxWidth` and `maxHeight` set.

### Input example

```json
{
  "urls": [
    "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png",
    "https://picsum.photos/id/10/1200/800.jpg"
  ],
  "outputFormat": "webp",
  "quality": 80,
  "maxWidth": 800,
  "stripMetadata": true
}
```

More examples:

- `{"outputFormat": "original", "quality": 75}` : same formats, smaller files.
- `{"maxWidth": 400, "maxHeight": 400, "resizeMode": "cover", "outputFormat": "jpeg"}` : 400x400 thumbnails.
- `{"lossless": true}` : PNG and WebP without any color loss.
- `{"datasetId": "<dataset id>", "datasetField": "imageUrl"}` : compress the images found in a scraper's output.

### Output

One dataset row per URL:

```json
{
  "index": 2,
  "sourceUrl": "https://picsum.photos/id/10/1200/800.jpg",
  "fileName": "10-1200-800.webp",
  "url": "https://api.apify.com/v2/key-value-stores/<storeId>/records/10-1200-800-1f2e3d4c5b6a.webp?signature=...",
  "originalBytes": 140884,
  "compressedBytes": 41210,
  "savedPercent": 70.8,
  "widthBefore": 1200,
  "heightBefore": 800,
  "widthAfter": 800,
  "heightAfter": 533,
  "format": "webp",
  "reduced": true,
  "status": "compressed",
  "error": null,
  "note": "converted jpg to webp; resized 1200x800 to 800x533"
}
```

- `status`: `compressed` (smaller, charged), `unchanged` (could not be made smaller, original returned, free), `skipped` (duplicate URL, maxImages, spending limit, SVG) or `failed` (download error, not an image, too many pixels). `error` says why.
- `url` is a signed link to the delivered file. Files are kept as long as the run's storage is kept.
- The `SUMMARY` record has the totals: images compressed, bytes saved, percent saved, charged images.

### How much does it cost to compress images

Pay per event: **$0.0017 per image that got smaller** (event `image-compressed`, about $1.70 per 1,000 images), plus the normal Apify platform usage of the run, which is small for typical images. Images that stay the same size, failed downloads and skipped URLs are free. Set a maximum spending limit on your run and it stops cleanly when reached.

### Use cases

- Speed up a website: compress and resize product photos and blog images to WebP.
- Cut storage and bandwidth for image libraries and CDNs.
- Prepare images for email, CMS uploads or marketplaces with a size limit.
- Shrink the images a scraper collected, straight from its dataset.
- Make thumbnails of one exact size.

### Limits (honest)

- The Actor downloads public image URLs you have the right to use. It does not log in and does not work around hotlink protection: a 401, 403 or 429 from the host is reported as `failed`.
- Max 25 MB per file by default (up to 100 MB) and 64 megapixels per image. SVG (vector) files are skipped.
- Lossy compression changes pixels. For a visually identical result use quality 80 or higher, or `lossless`.
- Animated GIF and WebP keep their animation only when the output format is `original` or `webp`. Animated AVIF is not supported. Other output formats keep the first frame and say so in `note`.
- Not every file can shrink: already well-optimized images often come back as `unchanged`.

### FAQ

**How do I compress images in bulk online without losing quality?**
Use quality 80-85 with the original format, or turn on `lossless`. Savings are smaller, and files that cannot shrink are returned unchanged for free.

**Which format gives the smallest images?**
Usually AVIF, then WebP, then JPEG for photos. For graphics with flat colors, PNG with color reduction or lossless WebP is often smallest. Try the same URLs with `outputFormat` set to each and compare `savedPercent`.

**Does it remove EXIF and GPS data?**
Yes, by default (`stripMetadata`). Orientation is applied to the pixels first. Turn the option off to keep EXIF and the color profile.

**Will it make small images bigger when resizing?**
No. `fit` and `cover` never upscale. `contain` pads the canvas but does not enlarge the picture.

**What happens to PNG transparency when I convert to JPEG?**
JPEG has no transparency, so it is replaced by a solid color (white by default, set `backgroundColor`). Use WebP, AVIF or PNG to keep it.

**Can I compress images from a dataset or a scraper's output?**
Yes. Pick the dataset in `datasetId` and set `datasetField` to the field with the image URL (a text value or a list).

### Related tools

- **Image Downloader** : download images from URLs or web pages in bulk, with dedupe and ZIP.
- **Video Converter & Compressor** : convert and shrink video files.
- **PDF Compressor** : reduce the size of PDF documents.

# Actor input Schema

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

Direct links to the images to compress, one per line. JPG, PNG, WebP, AVIF, GIF, BMP, TIFF and HEIC work. Example: https://example.com/photo.jpg. Use only images you have the right to process.

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

Optional. Pick an Apify dataset (for example the output of a scraper) and every image URL in the field below is compressed too. Example: a dataset ID such as aBcD1234eFgH5678i.

## `datasetField` (type: `string`):

Field of each dataset item that holds the image URL (or a list of URLs). Dotted paths work. Example: imageUrl or images.0.url. Default: url.

## `outputFormat` (type: `string`):

Convert every image to this format, or keep each one as it is. WebP and AVIF are usually the smallest. BMP, TIFF and HEIC become PNG or JPEG when you keep the original format. Example: webp.

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

Lossy quality for JPEG, WebP and AVIF (it also sets how many colors a PNG may be reduced to). 75-85 looks near-identical for most photos. Lower is smaller. Example: 75.

## `maxWidth` (type: `integer`):

Shrink images wider than this so they fit. Never enlarges a smaller image. 0 means no limit. Example: 1600.

## `maxHeight` (type: `integer`):

Shrink images taller than this so they fit. Never enlarges a smaller image. 0 means no limit. Example: 1200.

## `resizeMode` (type: `string`):

fit keeps the ratio and stays inside the box. cover and contain make every image exactly maxWidth x maxHeight (both required); cover crops from the center, contain pads with the background color. Example: fit.

## `stripMetadata` (type: `boolean`):

Remove EXIF (camera, GPS location), XMP and other metadata to save bytes and protect privacy. The orientation is always applied to the pixels first, so photos are never rotated wrongly. Colors are converted to sRGB before the profile is dropped.

## `progressive` (type: `boolean`):

Write JPEGs as progressive (they load blurry to sharp and are usually a few percent smaller).

## `lossless` (type: `boolean`):

Never lose pixel data: PNG is only re-compressed (no color reduction), WebP and AVIF are written lossless. Files shrink less, and lossless WebP of a photo can even grow, in which case the original is returned.

## `pngQuantize` (type: `boolean`):

Shrink PNGs by reducing them to a palette of up to 256 colors (keeps transparency) when that is smaller. Often cuts PNGs by 50-70%. Ignored when lossless is on.

## `backgroundColor` (type: `string`):

Used instead of transparency when converting to JPEG, and to pad images in contain mode. Hex color. Example: #ffffff.

## `skipIfNotSmaller` (type: `boolean`):

When compression would not make a file smaller, return the original bytes (reduced: false) instead of a bigger file. Those rows are never charged.

## `maxImages` (type: `integer`):

Most images processed in this run. URLs beyond this are skipped and not charged. Example: 100.

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

Images larger than this are skipped before they are fully downloaded. Images above 64 megapixels are always refused (memory safety).

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

How many images are processed at the same time. Default 4.

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

Optional. Download images through Apify Proxy or your own proxies. Usually not needed.

## Actor input object example

```json
{
  "urls": [
    "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png",
    "https://picsum.photos/id/10/1200/800.jpg"
  ],
  "datasetField": "url",
  "outputFormat": "original",
  "quality": 80,
  "maxWidth": 800,
  "maxHeight": 0,
  "resizeMode": "fit",
  "stripMetadata": true,
  "progressive": true,
  "lossless": false,
  "pngQuantize": true,
  "backgroundColor": "#ffffff",
  "skipIfNotSmaller": true,
  "maxImages": 100,
  "maxFileSizeMb": 25,
  "concurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

All result items of this run (the default dataset), as JSON, CSV, Excel and more.

## `records` (type: `string`):

Key-value store records: the run summary, notes on any problems, and any files.

# 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://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png",
        "https://picsum.photos/id/10/1200/800.jpg"
    ],
    "maxWidth": 800
};

// Run the Actor and wait for it to finish
const run = await client.actor("data-done-right/image-compressor").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://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png",
        "https://picsum.photos/id/10/1200/800.jpg",
    ],
    "maxWidth": 800,
}

# Run the Actor and wait for it to finish
run = client.actor("data-done-right/image-compressor").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://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png",
    "https://picsum.photos/id/10/1200/800.jpg"
  ],
  "maxWidth": 800
}' |
apify call data-done-right/image-compressor --silent --output-dataset

```

## MCP server setup

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

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/9CBwKqblG4B8LD0ag/builds/AqQYI3FnVpWsHcykl/openapi.json
