# Bulk Image Converter & Compressor (`bite-sized-insights/bulk-image-converter-compressor-and-resizer`) Actor

Convert, compress and resize images in bulk from URLs or uploaded files. Output WebP, AVIF, JPEG, PNG, GIF, TIFF or BMP, with HEIC input supported. Get public links and before/after file sizes for every image.

- **URL**: https://apify.com/bite-sized-insights/bulk-image-converter-compressor-and-resizer.md
- **Developed by:** [bite-sized-insights](https://apify.com/bite-sized-insights) (community)
- **Categories:** Developer tools, Automation, For creators
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 image converteds

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 Converter & Compressor - JPEG, PNG, WebP, AVIF

Convert and compress images in bulk. Give it a list of image URLs (or files you uploaded to a key-value store), pick
an output format and a quality, and get back smaller files with public links and a before/after size report for every
image.

### What this actor does

- **Converts between formats.** Read JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP and HEIC/HEIF (iPhone photos); write JPEG,
  PNG, WebP, AVIF, GIF, TIFF or BMP. Or keep each image's own format and only compress it.
- **Compresses with a quality setting** from 1 to 100. Pick WebP or AVIF for the smallest files, JPEG for maximum
  compatibility. For PNG, a lower quality reduces the number of colors.
- **Resizes to a maximum width and/or height.** Images are scaled down to fit inside the box without distortion, and
  are never enlarged. Switch off *Keep aspect ratio* to apply each limit to its own side.
- **Strips metadata.** Removes camera details and GPS location, converts colors to standard sRGB and rotates photos
  upright, so files get smaller and safer to publish. Turn it off to keep the metadata.
- **Handles transparency.** Transparent PNG/WebP/AVIF images stay transparent; for formats without transparency (JPEG,
  BMP) the transparent areas are filled with a background color you choose.
- **Keeps animations.** Animated GIF and WebP files stay animated when converted to GIF or WebP.
- **Converts uploaded files too.** Upload files to a key-value store and list their keys next to (or instead of) the
  URLs.
- **Reports the savings.** Every row shows the original and new size in bytes, the bytes and percentage saved, and the
  image dimensions before and after.
- **Delivers public links.** Converted files are saved to the run's key-value store; each dataset row links straight
  to its file.
- **Runs images concurrently** and adds each result to the dataset as soon as it is ready.

### Quick start

```json
{
    "urls": [
        "https://www.python.org/static/img/python-logo.png",
        "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"
    ],
    "outputFormat": "webp",
    "quality": 80,
    "maxWidth": 1600
}
```

Click **Start**. Converted files appear in the key-value store and the dataset as each image finishes.

### Input parameters

| Parameter | Type | Required | Description |
|---|---|---|---|
| `urls` | Array\[String] | No\* | Public image URLs to convert (up to 25 MB each). |
| `uploadKeys` | Array\[String] | No\* | Keys of image files you uploaded to a key-value store. |
| `uploadStoreName` | String | No | Key-value store holding the uploaded files. Empty = the default store. |
| `outputFormat` | String | No | `webp` (default), `jpeg`, `png`, `avif`, `original`, `gif`, `tiff` or `bmp`. |
| `quality` | Integer | No | 1-100, default 80. |
| `maxWidth` | Integer | No | Maximum width in pixels, 0 = no limit (default). |
| `maxHeight` | Integer | No | Maximum height in pixels, 0 = no limit (default). |
| `keepAspectRatio` | Boolean | No | Fit inside the maximum box without distortion. On by default. |
| `stripMetadata` | Boolean | No | Remove metadata and convert colors to sRGB. On by default. |
| `backgroundColor` | String | No | Hex color for filling transparency when the output has none. Default `#ffffff`. |

\* At least one image is required, from `urls` and/or `uploadKeys`. Up to 1000 images per run in total. Only public
http(s) URLs are accepted; entries pointing at private or local addresses, containing credentials, or otherwise
malformed are rejected as invalid input before any request is made. Duplicate entries are processed once.

#### Converting your own files

1. Create or open a key-value store in Apify Console and upload your images, or put them into the run's default
   key-value store through the API.
2. Enter the record keys (for example `holiday-01.heic`) under **Uploaded file keys**. If the files live in a named
   store, enter its name under **Key-value store name for uploaded files**.

### Output

One dataset row per input image, in the order of the input (URLs first, then uploaded files). The converted file
itself is stored in the run's key-value store under the key `<index>-<name>.<extension>`, and `outputUrl` is its
public link.

#### Successful conversion

```json
{
    "index": 1,
    "source": "https://www.python.org/static/img/python-logo.png",
    "sourceType": "url",
    "status": "success",
    "outputUrl": "https://api.apify.com/v2/key-value-stores/xxxxxxxxxxxxxxxxx/records/00001-python-logo.webp",
    "outputKey": "00001-python-logo.webp",
    "sourceFormat": "png",
    "outputFormat": "webp",
    "sourceBytes": 15770,
    "outputBytes": 6178,
    "bytesSaved": 9592,
    "savedPercent": 60.8,
    "sourceWidth": 601,
    "sourceHeight": 203,
    "outputWidth": 601,
    "outputHeight": 203,
    "error": null
}
```

#### Failed image

```json
{
    "index": 2,
    "source": "https://example.com/not-an-image.html",
    "sourceType": "url",
    "status": "failed",
    "outputUrl": null,
    "outputKey": null,
    "sourceFormat": null,
    "outputFormat": null,
    "sourceBytes": null,
    "outputBytes": null,
    "bytesSaved": null,
    "savedPercent": null,
    "sourceWidth": null,
    "sourceHeight": null,
    "outputWidth": null,
    "outputHeight": null,
    "error": "The file is not a supported or readable image."
}
```

`bytesSaved` and `savedPercent` are negative when the converted file is larger than the original, which can happen
when converting an already well-compressed image to a different format. Choose a lower quality or another format in
that case.

An image fails (and is not charged) when it cannot be downloaded, is not a readable image, is larger than 25 MB, has
too many pixels to process safely, or its URL points to a private or internal address. The `error` field says which. A
problem with the conversion service's credentials does not produce a row; it fails the whole run with an error
message.

### Pricing: pay per converted image

Only successfully converted images are billed. Failed images are free. A tiny flat per-run start fee also applies, and
Apify's platform dataset-item fee ($0.00001 per row) applies to every row written to the dataset, including failed
rows.

| Event | Price |
|---|---|
| Image converted | $0.008 per image ($8.00 per 1,000 images) |
| Run start | $0.00005 per run |

### FAQ

**Which formats can I convert to?** JPEG, PNG, WebP, AVIF, GIF, TIFF and BMP. HEIC/HEIF files can be read but not
written.

**Is there a size limit?** Each source file may be up to 25 MB and up to 50 megapixels. Larger images are reported as
failed rows.

**Are my uploaded files public?** The converted files are stored in the run's key-value store and are reachable
through the links in the dataset. Your source files stay where you uploaded them.

**Why is a converted file sometimes bigger?** Re-encoding an image that is already heavily compressed can increase its
size. Lower the quality, choose WebP or AVIF, or reduce the maximum width.

# Actor input Schema

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

Public http(s) image URLs, up to 25 MB each. Replace the sample if you only use uploads.

## `uploadKeys` (type: `array`):

Keys of image files you uploaded to a key-value store. Converted like URLs.

## `uploadStoreName` (type: `string`):

Name of the key-value store with the uploaded files. Empty = the run's default store.

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

Format of the converted files. Keep original format only compresses and resizes.

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

1 = smallest file, 100 = best quality. For PNG, below 100 reduces the number of colors.

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

Shrink images wider than this many pixels. 0 = no limit. Images are never enlarged.

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

Shrink images taller than this many pixels. 0 = no limit. Images are never enlarged.

## `keepAspectRatio` (type: `boolean`):

Fit images inside the maximum size without distortion. Off: each limit applies per side.

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

Remove camera data and GPS location, convert colors to sRGB and rotate photos upright.

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

Hex color (e.g. #ffffff) that replaces transparency when the output has none (JPEG, BMP).

## Actor input object example

```json
{
  "urls": [
    "https://www.python.org/static/img/python-logo.png",
    "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"
  ],
  "outputFormat": "webp",
  "quality": 80,
  "maxWidth": 0,
  "maxHeight": 0,
  "keepAspectRatio": true,
  "stripMetadata": true,
  "backgroundColor": "#ffffff"
}
```

# Actor output Schema

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

One row per input image with the link to the converted file and file sizes

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

The converted image files in the run's key-value store

# 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.python.org/static/img/python-logo.png",
        "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bite-sized-insights/bulk-image-converter-compressor-and-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 = { "urls": [
        "https://www.python.org/static/img/python-logo.png",
        "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("bite-sized-insights/bulk-image-converter-compressor-and-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 '{
  "urls": [
    "https://www.python.org/static/img/python-logo.png",
    "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"
  ]
}' |
apify call bite-sized-insights/bulk-image-converter-compressor-and-resizer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bite-sized-insights/bulk-image-converter-compressor-and-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/aP98JGiG6cD4cB2rv/builds/JDbBbIv2sX2f0YT3a/openapi.json
