# Bulk Image Compressor & Converter: Images to WebP, AVIF (`lineagersiui/bulk-image-converter`) Actor

Bulk image compressor and converter for image URLs: convert to WebP, AVIF, JPEG or PNG, compress by quality or toward a target file size (best effort), resize (no upscaling by default), remove EXIF/GPS by default. Up to 500 images per run. $1 per 1,000 images. Free demo.

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

## Pricing

$1.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

## Image Converter & Compressor: Bulk WebP, AVIF, JPEG, PNG

**Convert and compress images in bulk.** Give it links to image files. For each image it:

- converts to **WebP, AVIF, JPEG or PNG**;
- compresses to a **quality** you choose, or to a **target file size** (for example "under 150 KB");
- optionally **resizes** to a width and/or height, without upscaling unless you ask;
- **removes EXIF, GPS location and camera data by default**, rotates the image upright and converts colours to sRGB.

Converted files are saved to the run's key-value store. You also get one dataset row per image with the byte savings.

### Use this Actor when…

Use this Actor when:

- you have a list of product, catalogue or blog images and need them as WebP or AVIF for a faster site;
- you need every file under a size limit (marketplaces, email, CMS uploads) without tuning each one by hand;
- you want photos cleaned of GPS location and camera metadata before publishing;
- you run no-code automations (Make, Zapier, n8n) and need a simple "URL in, optimized file out" step for up to 500 images per run.

Inputs: `imageUrls` (required), `confirmRights: true` (required), `outputFormat` (`webp`, `avif`, `jpeg`, `png`), `quality` (1–100, default 80), `targetMaxKB`, `width`, `height`, `fit`, `allowUpscale`, `stripMetadata` (default on).

### Try it free first

Run it with an empty URL list. A **free demo** converts 3 small public-domain sample images from Wikimedia Commons. It isn't billed, so you can see the output files and the report.

### Image compression and resize

- **Compress by quality:** `quality` 1 to 100 (default 80) for WebP, AVIF and JPEG; PNG is lossless unless a target size is set.
- **Compress to a file size:** `targetMaxKB` lowers quality step by step (at most 7 encodes) until each file is under the target. Best effort: if it cannot be reached, the smallest result is saved and `targetMet` is `false`.
- **Resize:** `width` and/or `height` with `fit`; images are not enlarged unless you turn on `allowUpscale`.

### What it can't do

- **No HEIC/HEIF (iPhone) input** and **no SVG input.** SVG is refused for safety (it can contain scripts and external references). Both are reported as `unsupported_format` and aren't billed.
- **No upscaling by default.** Images smaller than your width/height stay at their size unless you turn on `allowUpscale`.
- **Animated images become still images.** Animated GIF and WebP (and multi-page TIFF) are converted to their **first frame**. Files with more than 100 frames are rejected (`too_many_frames`).
- **Very large images are refused:** more than 40 megapixels per frame (`too_many_pixels`) or more than 25 MB per file (`too_large`).
- **Output is limited to 40 megapixels** (width × height after resizing or upscaling). Larger requested outputs are rejected as `output_too_large` and aren't billed.
- **Removing metadata removes everything,** including copyright, creator and licence fields. Turn off **Remove metadata** if you need to keep them (this also keeps GPS and camera data).
- **Input is URLs only**, no file uploads. The links must be publicly reachable.
- **Target size is best effort.** If a file can't reach your target even at the lowest quality, the smallest version is saved and `targetMet` is `false`. It doesn't shrink dimensions to hit a target.

### How to convert and compress images in bulk

1. Paste your **image URLs** (up to 500 per run, 25 MB each, 50 per linked site), for example `https://example.com/images/product-1.jpg`.
2. Tick **I own these images or am licensed to process them**. Runs without it are refused before anything is downloaded or charged (the free demo doesn't need it).
3. Choose the **output format** and a **quality**, or set a **target maximum size in KB**.
4. Optionally set **width** and/or **height** and how the image should **fit**.
5. Leave **Remove metadata** on, unless you need to keep the original EXIF.

### Output: converted files and byte-savings report

Each converted file is stored in the run's **key-value store** under `kvKey` (for example `image-0001-3f9a2c1b7d4e.webp`).

Each dataset item has:

- `url`, `status` (`converted`, `rejected`, `failed`, `duplicate` or `skipped`);
- `inputFormat`, `outputFormat`, `inputBytes`, `outputBytes`, `savedPercent`, `width`, `height`, `kvKey`;
- `index` (position in your list; with parallel processing, rows may arrive out of order);
- `quality` (the quality used; `null` for lossless PNG), `targetMet` (only with a target size), `firstFrameOnly` (for animated inputs), `alreadyDelivered` (an image converted and billed before a platform restart of the same run);
- `error` when something went wrong (none of these are billed):
  - **the file:** `unsupported_format`, `too_many_pixels`, `too_many_frames`, `output_too_large`, `corrupt_image`, `timeout` (conversion took too long), `too_complex` (needed too much memory) or `convert_error`;
  - **the download:** `http_404` and other `http_<status>` codes, `too_large`, `timeout`, `network_error` (including names that don't resolve), `read_error` or `too_many_redirects`;
  - **the address:** `invalid_url`, `scheme_not_allowed`, `port_not_allowed`, `blocked_private_address` or `denied_host`. The same checks on a redirect target are reported with a `redirect_` prefix, for example `redirect_blocked_private_address`, `redirect_scheme_not_allowed`, `redirect_port_not_allowed`, `redirect_invalid_url` or `redirect_denied_host`;
  - **the run:** `duplicate_image` (the same file under another URL), `run_limit_reached`, `time_limit_reached`, `spending_limit_reached`, `billing_stopped` (charging failed, so paid work stopped), `write_failed` (the output couldn't be saved) or `internal_error`.

The `url` field holds the address as checked, with any `user:password@` part and `#fragment` removed.

A `SUMMARY` record in the key-value store holds the counts and total bytes saved.

### Safe by design

- **Untrusted files are handled carefully.** Files are accepted by their actual bytes (not the URL or the server's content type). Each image is decoded in an isolated worker with input and output pixel, frame, time and memory limits.
- **Addresses:** private and internal network addresses are refused, and every redirect is checked again before it is followed. Only `http` and `https` on the standard ports.
- **What it never sends:** cookies, credentials or proxy headers. It never tries to get around access controls or anti-bot protection.
- **Pacing:** at most one request at a time per server, at least 500 ms apart, and at most 50 images per linked site per run (counted by the site in the URL you give).
- **Identification:** the user agent is `BulkImageConverter/1.0`, with a link to this page.
- **Privacy:** original images are never stored. Logs hold counts only, never URLs or image content. Metadata (including GPS location) is removed from outputs by default.
- To report misuse, open an issue on this Actor's **Issues** tab.

### Pricing

- **Pay per event:** each successfully converted and saved image is one `image-converted` event.
- **Not billed:** failed downloads, rejected or unsupported files, duplicates (the same file under another URL), images whose output couldn't be saved, images not processed because of a limit, and the demo images.
- The price is shown on the Pricing tab. If the Pricing tab also lists Apify's standard per-run start event, that is charged once per run, as shown there. You can cap the maximum charge per run in Apify's run options; the run stops at your limit.

### Terms of use

- **Your rights:** only process images you own or are licensed to process. You are responsible for copyright compliance.
- **Personal data:** if images show people or contain personal data, you are responsible for having a lawful basis to process them.
- **Where files go:** converted files are stored only in your run's key-value store and dataset. The developer doesn't keep or view them.
- **Limits per run:** 500 images, 25 MB per image, 40 megapixels per frame in and 40 megapixels out, and 50 images per linked site.

### Support

Questions, bugs and feature requests: open an issue on this Actor's **Issues** tab.

### About

- **Independent:** made by an independent developer. Unofficial; not affiliated with or endorsed by Apify.
- **Built with AI:** built and maintained with the help of AI tools, under the developer's direction.
- **Credits:** image processing by [sharp](https://sharp.pixelplumbing.com) (Apache-2.0) and [libvips](https://www.libvips.org) (LGPL-3.0-or-later).

### Open-source licences

This Actor uses these libraries, unmodified, from the public npm registry:

- **sharp 0.35.5:** Apache License 2.0, © Lovell Fuller and contributors. Source: https://github.com/lovell/sharp. Licence: https://www.apache.org/licenses/LICENSE-2.0
- **libvips and bundled libraries (@img/sharp-libvips-linuxmusl-x64 1.3.4):** libvips is under the GNU LGPL v3.0 or later, © John Cupitt and contributors. The package also bundles libraries under LGPL-3.0, BSD-2-Clause (aom, with the AOM patent licence) and other permissive licences, listed at https://github.com/lovell/sharp-libvips/blob/v1.3.4/THIRD-PARTY-NOTICES.md. Corresponding source: https://github.com/lovell/sharp-libvips (tag v1.3.4) and https://github.com/libvips/libvips. The libraries are dynamically linked shared libraries and are not modified.
- **Apify SDK 3.7.2:** Apache License 2.0.

# Actor input Schema

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

Public http(s) links to image files (JPEG, PNG, WebP, GIF, AVIF or TIFF): up to 500 per run, 25 MB each, 50 per linked site. SVG and HEIC are not supported. Example: https://example.com/images/product-1.jpg. Leave empty for the free demo.

## `confirmRights` (type: `boolean`):

Required for non-demo runs. Only process images you own or are licensed to process, including any personal data in them. You are responsible for copyright and data-protection compliance.

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

Format of the converted files. WebP is a good default for the web; AVIF is smaller but slower to encode; PNG is lossless.

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

1-100 for WebP, AVIF and JPEG. PNG is lossless unless a target size is set. With a target size, this is the highest quality tried.

## `targetMaxKB` (type: `integer`):

Optional. Lowers quality step by step (at most 7 encodes) to get each file under this size. If it can't be reached, the smallest result is saved and targetMet is false.

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

On (recommended): EXIF, GPS location, XMP and IPTC are removed, the image is rotated upright, and colours are converted to sRGB. Off: the original metadata is kept.

## `width` (type: `integer`):

Optional maximum width. Leave empty to keep the original size. Output is limited to 40 megapixels (larger results are rejected as output_too_large, not billed).

## `height` (type: `integer`):

Optional maximum height. Leave empty to keep the original size. Output is limited to 40 megapixels.

## `fit` (type: `string`):

How the image fits the width/height box. Used only when width or height is set.

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

Off: images smaller than the box are never enlarged. On: small images are enlarged to the box, up to 40 megapixels of output.

## `timeLimitSecs` (type: `integer`):

No new images are started after this time. Unprocessed images are not charged.

## Actor input object example

```json
{
  "confirmRights": false,
  "outputFormat": "webp",
  "quality": 80,
  "stripMetadata": true,
  "fit": "inside",
  "allowUpscale": false,
  "timeLimitSecs": 3000
}
```

# Actor output Schema

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

No description

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

No description

## `summary` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("lineagersiui/bulk-image-converter").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("lineagersiui/bulk-image-converter").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 '{}' |
apify call lineagersiui/bulk-image-converter --silent --output-dataset

```

## MCP server setup

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

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/gesbc9jbwa80ihyej/builds/Ew6kJjeAkhlWSoVLg/openapi.json
