# Images to PDF Converter — Merge JPG & PNG into One PDF (`actor-forge/images-to-pdf`) Actor

Merge JPG, PNG, HEIC, WebP and other images from URLs into one PDF (or one PDF per image): A4, Letter or fit-to-image pages, margins, auto-rotation, compression. Download link per PDF. $0.022 for a 10-image PDF.

- **URL**: https://apify.com/actor-forge/images-to-pdf.md
- **Developed by:** [ActorForge](https://apify.com/actor-forge) (community)
- **Categories:** Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 image processeds

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

## Images to PDF Converter — Merge JPG & PNG into One PDF

Merge JPG, PNG, HEIC, WebP and other images from URLs into one PDF (or one PDF per image): A4, Letter or fit-to-image pages, margins, auto-rotation, compression. Download link per PDF. $0.022 for a 10-image PDF.

**Merge images into a PDF online, in bulk.** Paste links to **JPG, PNG, HEIC (iPhone), WebP, AVIF, GIF, TIFF or SVG** images and get **one PDF with one image per page, in the order of your list**, with a **direct download link**. Pick **A4, US Letter or fit-to-image pages**; A4 and Letter pages turn **portrait or landscape to match each image**, which is centred inside your **margin**. Photos are **rotated upright** from their EXIF orientation and compressed as JPEG at the quality you choose, and screenshots, scans and graphics in PNG, GIF, TIFF or SVG are embedded **losslessly** so text stays sharp. Want **one PDF per image** instead (JPG to PDF, PNG to PDF)? Switch the mode. Optionally **resize** large photos first to keep the PDF small. Use it to turn photographed receipts, invoices, delivery notes and forms into a single PDF for accounting, insurance claims or archives, to bundle product or property photos into a PDF catalogue, to make a printable PDF from a gallery, or as an images-to-PDF step for Make, n8n, Zapier and AI agents. **Pricing: $0.002 per page image + $0.002 per PDF, so a 10-image PDF costs $0.022** with no compute bill on top (other images-to-PDF actors charge up to $0.055 for the same 10 images). Failed images are never charged and simply leave no page.

### What data does it return?

Every run outputs clean, schema-validated rows like these:

| fileName | format | pageCount | originalBytes | outputBytes | sourceUrl |
| --- | --- | --- | --- | --- | --- |
| images.pdf | pdf | 10 | 18634112 | 6120448 | https://example.com/receipts/2026-10-01.jpg |
| 00001-scan-page-1.pdf | pdf | 1 | 412880 | 398112 | https://example.com/scans/scan-page-1.png |

### How much does it cost?

Transparent pay-per-event pricing — you only pay for what you get, and the
actor **always respects your run budget**: set a maximum total charge and it
stops cleanly at the cap instead of overrunning.

| Event | Price | Charged | Worked example |
| --- | --- | --- | --- |
| `image-processed` | $0.002 | per image placed on a PDF page (orientation, resizing and compression included) | A 10-page PDF = 10 × $0.002 = $0.02 for the pages |
| `pdf-created` | $0.002 | per PDF file created (each page image is also one image-processed) | 10 images merged into one PDF = $0.02 + $0.002 = $0.022; 100 images into one PDF = $0.202; 10 images as 10 separate PDFs = $0.04 |
| `heic-decoded` | $0.001 | per HEIC/HEIF source image decoded (iPhone photos; added on top of image-processed) | An iPhone HEIC photo on a page = $0.002 + $0.001 |
| `large-image` | $0.002 | per source image over 25 megapixels (all frames count for kept animations; added on top of image-processed; up to 50 MP accepted) | A 36 MP camera photo = $0.002 + $0.002 = $0.004; a 12 MP phone photo has no add-on |
| `apify-actor-start` | $0.00005 | per run per GB of memory (platform start fee) | One run at 1 GB = $0.00005 |

### Input options

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `imageUrls` | array | yes | — | Direct links to the images, in page order (JPEG, PNG, HEIC/HEIF, WebP, AVIF, GIF, TIFF or SVG; the format is detected from the file itself). Up to 25 MB and 50 megapixels per image. |
| `format` | string | no | `"pdf"` | PDF (default) builds PDF files from your images. The other formats convert the images themselves (WebP, AVIF, JPEG, PNG) instead. |
| `quality` | integer | no | `85` | JPEG quality for photos inside the PDF: lower = smaller PDF. 85 (default) looks identical on screen and in print; 70 roughly halves the size. PNG, GIF, TIFF and SVG images are embedded losslessly. |
| `width` | integer | no | — | Optional: shrink images wider than this before putting them in the PDF (makes the PDF much smaller; 2000 px is plenty for A4). Empty = keep the original size. Image pixels are never upscaled (fitting to the PDF page is separate). |
| `height` | integer | no | — | Resize so the image is at most this tall. Empty = keep the original height. |
| `fit` | string | no | `"inside"` | When both width and height are set: 'inside' keeps the aspect ratio within the box, 'cover' crops to fill the box exactly, 'contain' pads to the box with the background colour. |
| `background` | string | no | `"#ffffff"` | Hex colour used for padding ('contain') and for transparent areas when converting to JPEG. |
| `stripMetadata` | boolean | no | `true` | Remove EXIF, GPS location, camera details, XMP and IPTC from the output (photos are rotated upright first). Smaller files and no leaked locations. Each row still reports whether the original had EXIF / GPS. |
| `maxFileSizeKb` | number | no | — | Optional. Lowers the quality step by step (and, if needed, the dimensions) until each image fits under this size. Rows show the quality used and whether the target was met. |
| `keepAnimation` | boolean | no | `true` | Animated GIF or WebP converted to WebP keep all frames. Off = first frame only. AVIF, JPEG and PNG output always use the first frame. |
| `outputMode` | string | no | `"links"` | 'Links' saves each image with its own download link. 'ZIP' bundles all images into ZIP files (up to 200 MB each; links in the OUTPUT record). 'Both' does both. A merged PDF is always a download link. |
| `filenamePattern` | string | no | `"{index}-{name}"` | Tokens: {index} (00001…), {name} (original file name), {width}, {height}, {format}. The extension is added automatically; duplicate names get a -2, -3… suffix. |
| `maxImages` | integer | no | `1000` | Stop after converting this many images. |
| `pdfMode` | string | no | `"merge"` | 'Merge' puts all images into one PDF, one image per page, in the order of your list. 'Separate' makes one PDF per image. |
| `pdfPageSize` | string | no | `"a4"` | 'Fit image' makes each page exactly the size of its image (96 dpi). A4 and Letter pages turn portrait or landscape to match each image, which is scaled to fill the page inside the margin. |
| `pdfMarginMm` | integer | no | `10` | White margin around the image on A4 and Letter pages. 'Fit image' pages have no margin. |
| `pdfFileName` | string | no | `"images"` | Name of the merged PDF (without .pdf). Very large merges are split into parts: name.pdf, name-part-2.pdf, ... |

### Limits & honest notes

- Input: direct image URLs, in page order. Images that fail to download or decode are reported as error rows (not charged) and leave no page; the PDF keeps the order of the rest.
- Each image can be up to 25 MB and 50 megapixels; sources over 25 MP add `large-image` ($0.002) and HEIC photos add `heic-decoded` ($0.001). Animated GIFs use the first frame.
- One image per page. 'Fit image' pages are the image size at 96 dpi; on A4/Letter pages images are scaled to fill the page inside the margin (small images are enlarged to fit).
- Photos are re-encoded as baseline JPEG at your quality setting (rotated upright, sRGB); PNG, GIF, TIFF and SVG are embedded as lossless PNG. Transparent areas in JPEG pages become the background colour.
- A merged PDF holds up to about 128 MB of images at 1 GB memory (more with more memory); bigger merges are split into name.pdf, name-part-2.pdf, and so on, and each part is one `pdf-created`.
- No OCR: the PDF contains images, not searchable text.
- Download links work for the lifetime of the run's storage (Apify's default retention for your plan). ZIP files are split into parts of up to 200 MB.
- Internal and private network addresses are always refused, including through redirects or DNS tricks. Only convert images you have the right to use.
- Respects your run budget: set a maximum total charge and the actor stops cleanly at the cap.

### Related ActorForge actors

- [Image Converter & Compressor](https://apify.com/actor-forge/image-converter)
- [HEIC to JPG Converter](https://apify.com/actor-forge/heic-to-jpg)
- [PDF OCR](https://apify.com/actor-forge/pdf-ocr) — make a scanned PDF searchable

### Changelog

- **2026-10-19** — Initial release: merge images into one PDF or one PDF per image, A4/Letter/fit pages, margins, auto-rotation, HEIC support.

***

*Built and maintained by **ActorForge**. Reliability first: every actor in the
portfolio is monitored by an automated nightly self-test, and breakages are
typically fixed the same day.*

# Actor input Schema

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

Direct links to the images, in page order (JPEG, PNG, HEIC/HEIF, WebP, AVIF, GIF, TIFF or SVG; the format is detected from the file itself). Up to 25 MB and 50 megapixels per image.

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

PDF (default) builds PDF files from your images. The other formats convert the images themselves (WebP, AVIF, JPEG, PNG) instead.

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

JPEG quality for photos inside the PDF: lower = smaller PDF. 85 (default) looks identical on screen and in print; 70 roughly halves the size. PNG, GIF, TIFF and SVG images are embedded losslessly.

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

Optional: shrink images wider than this before putting them in the PDF (makes the PDF much smaller; 2000 px is plenty for A4). Empty = keep the original size. Image pixels are never upscaled (fitting to the PDF page is separate).

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

Resize so the image is at most this tall. Empty = keep the original height.

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

When both width and height are set: 'inside' keeps the aspect ratio within the box, 'cover' crops to fill the box exactly, 'contain' pads to the box with the background colour.

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

Hex colour used for padding ('contain') and for transparent areas when converting to JPEG.

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

Remove EXIF, GPS location, camera details, XMP and IPTC from the output (photos are rotated upright first). Smaller files and no leaked locations. Each row still reports whether the original had EXIF / GPS.

## `maxFileSizeKb` (type: `number`):

Optional. Lowers the quality step by step (and, if needed, the dimensions) until each image fits under this size. Rows show the quality used and whether the target was met.

## `keepAnimation` (type: `boolean`):

Animated GIF or WebP converted to WebP keep all frames. Off = first frame only. AVIF, JPEG and PNG output always use the first frame.

## `outputMode` (type: `string`):

'Links' saves each image with its own download link. 'ZIP' bundles all images into ZIP files (up to 200 MB each; links in the OUTPUT record). 'Both' does both. A merged PDF is always a download link.

## `filenamePattern` (type: `string`):

Tokens: {index} (00001…), {name} (original file name), {width}, {height}, {format}. The extension is added automatically; duplicate names get a -2, -3… suffix.

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

Stop after converting this many images.

## `pdfMode` (type: `string`):

'Merge' puts all images into one PDF, one image per page, in the order of your list. 'Separate' makes one PDF per image.

## `pdfPageSize` (type: `string`):

'Fit image' makes each page exactly the size of its image (96 dpi). A4 and Letter pages turn portrait or landscape to match each image, which is scaled to fill the page inside the margin.

## `pdfMarginMm` (type: `integer`):

White margin around the image on A4 and Letter pages. 'Fit image' pages have no margin.

## `pdfFileName` (type: `string`):

Name of the merged PDF (without .pdf). Very large merges are split into parts: name.pdf, name-part-2.pdf, ...

## Actor input object example

```json
{
  "imageUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg",
    "https://www.gstatic.com/webp/gallery3/1.png",
    "https://www.gstatic.com/webp/gallery/2.jpg"
  ],
  "format": "pdf",
  "quality": 85,
  "fit": "inside",
  "background": "#ffffff",
  "stripMetadata": true,
  "keepAnimation": true,
  "outputMode": "links",
  "filenamePattern": "{index}-{name}",
  "maxImages": 1000,
  "pdfMode": "merge",
  "pdfPageSize": "a4",
  "pdfMarginMm": 10,
  "pdfFileName": "images"
}
```

# Actor output Schema

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

One row per PDF with a download link, page count, size and the source image of every page.

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

Totals (images converted, bytes before and after) and download links for ZIP and PDF 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 = {
    "imageUrls": [
        "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg",
        "https://www.gstatic.com/webp/gallery3/1.png",
        "https://www.gstatic.com/webp/gallery/2.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("actor-forge/images-to-pdf").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": [
        "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg",
        "https://www.gstatic.com/webp/gallery3/1.png",
        "https://www.gstatic.com/webp/gallery/2.jpg",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("actor-forge/images-to-pdf").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": [
    "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg",
    "https://www.gstatic.com/webp/gallery3/1.png",
    "https://www.gstatic.com/webp/gallery/2.jpg"
  ]
}' |
apify call actor-forge/images-to-pdf --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,actor-forge/images-to-pdf"
        }
    }
}
```

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/4bzZWOSQbyqu2TXRn/builds/7Xf5UoNcfHakeYK9C/openapi.json
