Image Converter & Compressor: WebP, AVIF, JPEG, PNG
Pricing
from $0.80 / 1,000 image converteds
Image Converter & Compressor: WebP, AVIF, JPEG, PNG
Convert and compress images in bulk to WebP, AVIF, JPEG or PNG, with quality and resize settings. Keeps transparency and animation, turns photos upright, converts colour profiles to sRGB, strips EXIF and GPS. Damaged files are refused, not padded, and not charged.
Pricing
from $0.80 / 1,000 image converteds
Rating
0.0
(0)
Developer
WrenTools
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare
Convert a batch of images to WebP, AVIF, JPEG or PNG in one run, smaller and ready for the web. Give it direct links to your images, or send them as base64. Each converted image is stored in the run's key-value store with a download link, and the dataset tells you its size before and after, its dimensions and anything the conversion changed.
What you get
- Four output formats. WebP, AVIF, JPEG and PNG, from JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP and other common formats.
- Quality and size settings. Set
quality(1-100) or keep each format's default (WebP 80, JPEG 85, AVIF 60). SetmaxWidthand/ormaxHeightto shrink large images to fit, keeping their proportions. Small images are never enlarged. - Photos come out upright. A phone photo stored sideways with an EXIF orientation tag is turned upright before the tag is removed, so it does not come out rotated.
- Colours stay the same. An image with a wide-gamut colour profile (Display P3, for example) is converted to sRGB, so it looks the same once the profile is gone.
- Transparency is kept in WebP, AVIF and PNG, including transparent palette PNGs. JPEG has no transparency, so
transparent areas are filled with the
backgroundcolour you choose (white by default), never black. - Animations stay animated. An animated GIF, PNG, WebP or AVIF converted to WebP, AVIF or PNG keeps every frame and its timing, and plays once or loops as the original did. JPEG holds one frame, so you get the first, and the item says so.
- EXIF, GPS and XMP are removed. The camera, the location and other metadata are not written to the output.
- 16-bit images come out right, scaled to 8 bits rather than clipped to a blank white or black picture.
- Damaged files are refused, not padded. An image that is cut short (a failed download, a half-copied file) is
reported as
damaged-imageand not charged. It is never written out with invented rows or grey bars. - Every output is checked. Each converted file is read back before it is stored: it must be the format you asked for, at the expected size, with every frame. A file that fails is reported and not charged.
- An image too large for its format is refused with the reason. WebP allows at most 16,383 pixels a side, so a
long screenshot is refused with the formats that can take it, or you can set
maxHeight. - One bad image does not sink the run. A link that fails, a file that is not an image, or a damaged file is reported in its place, and the rest are converted.
Each of these is a test in the Actor's suite, run on generated images before every release.
Respectful by design
- Only the URLs you list are downloaded, one request each. Pages are not crawled and links are not followed. The
site's robots.txt is read first and obeyed, and so is the robots.txt of any site a link redirects to: a link that
redirects somewhere its robots.txt refuses is not requested there and is reported as
robots-disallowed-redirect. Downloads from one site are spaced (500 ms by default). No proxy, no browser, no login. - Only public internet addresses are fetched. A URL or redirect into a private, loopback or link-local network is refused.
- No AI and no third-party service: the conversion runs inside the Actor with Pillow and its codecs.
Convert only images you have the right to copy.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
fileUrls | array | - | Direct links to images. Duplicates are dropped. |
filesBase64 | array | - | Images as base64 strings, or {"name": "photo.jpg", "data": "<base64>"}. A data: URL prefix is accepted. |
outputFormat | string | webp | webp, avif, jpeg or png. |
quality | integer | per format | 1-100. WebP 80, JPEG 85, AVIF 60 when empty. Not used for PNG (lossless). |
maxWidth, maxHeight | integer | - | Shrink to fit; never enlarge. |
background | string | #ffffff | What transparency becomes in a JPEG. |
keepAnimation | boolean | true | Off writes the first frame only. |
maxFileSizeMb | integer | 50 | Up to 200. Larger images are skipped and not charged. |
requestDelayMs | integer | 500 | Pause between downloads from one site. |
Give fileUrls, filesBase64 or both.
Output
One dataset item per image, in input order:
{"source": "https://example.com/photos/beach.jpg", "url": "https://example.com/photos/beach.jpg","finalUrl": "https://example.com/photos/beach.jpg", "status": "ok","key": "0001-beach.webp", "fileName": "beach.webp","downloadUrl": "https://api.apify.com/v2/key-value-stores/<store id>/records/0001-beach.webp","inputFormat": "JPEG", "inputBytes": 2480133, "inputWidth": 3000, "inputHeight": 4000, "inputFrames": 1,"outputFormat": "WEBP", "outputBytes": 312904, "width": 1200, "height": 1600, "frames": 1, "savedPercent": 87.4,"notes": ["turned upright from its EXIF orientation", "resized from 3000x4000 to 1200x1600"], "error": null}
A refused image:
{"source": "https://example.com/photos/broken.jpg", "status": "error", "key": null, "inputBytes": 1048576,"error": {"code": "damaged-image", "message": "the image is damaged or cut short (image file is truncated); not converted, not charged. ..."}}
Error codes: damaged-image, not-an-image, too-large-for-format, too-many-pixels, output-check-failed,
file-too-large, fetch-failed, robots-disallowed, robots-disallowed-redirect, invalid-url, invalid-base64,
conversion-timeout (the run's timeout came while it was converting).
A file whose whole reply takes longer than its time limit is a fetch-failed row whose message starts
deadline-exceeded, and the run goes on to the next. The limit is the largest file maxFileSizeMb
allows at 333 kB/s, between 60 s and 600 s (150 s at the default 50 MB). So a server that sends a file
very slowly cannot hold the run.
Key-value store record SUMMARY: images requested, converted and failed, bytes before and after, the saving, the
megabytes charged, and why the run stopped early if it did.
Files in a run's default storage are kept for as long as your Apify plan keeps unnamed storage (7 days on the free plan). Copy anything you need to keep longer.
Pricing
Pay per event, no start fee, and nothing for images that fail or are refused:
| Event | Price | Per 1,000 |
|---|---|---|
image-converted (one image converted, checked and stored) | $0.0008 | $0.80 |
megabyte-processed (each started megabyte of the larger of the image's input and output, at least one) | $0.0004 | $0.40 |
So a 300 KB web image costs $0.0012, a 1.5 MB image $0.0016, and a 5.7 MB 12-megapixel photo $0.0032. Converting a photo to PNG usually makes it several times larger, and the larger size is what counts. When you set a maximum charge for a run, the Actor stops before an image the remainder cannot pay for.
Limits
- Images only, one URL each. It does not crawl a page for its images.
- Pixels per image depend on the run's memory: about 27 megapixels at the default 1,024 MB, 60 at 2,048 MB and 127
at 4,096 MB (an animation counts every frame). A larger image is refused as
too-many-pixelsand not charged. These come from the peak memory we measured converting 12- and 50-megapixel photos to each format. - Speed: converting one 12-megapixel photo on our own machine (one full CPU core) took about 0.2 s to JPEG, 1.5 s to AVIF, 1.8 s to PNG and 2.9 s to WebP. On Apify at the default 1,024 MB, a whole run converting one such photo took 3.8 s to WebP and 2.9 s to AVIF, start-up included (measured 2026-11-02).
- Colour profiles are converted to sRGB; the output carries no profile. 16-bit images come out as 8-bit.
- A multi-page TIFF gives its first page.
- 200 MB per input file at most.
- A run stops early, before its timeout, so its results are saved: 60 s before it (a fifth of the time for a run
shorter than 5 minutes) it starts no new image, and a download still running then is cut and reported as
fetch-failed(deadline-exceeded), not charged. An image still converting 10 s before the timeout is cut (half the margin, for a run shorter than 5 minutes): it is reported asconversion-timeout, not stored and not charged. Every image converted by then is stored and charged, images not started are not in the dataset and not charged, andSUMMARY.stoppedReasonsays why the run stopped.