# KDP Paperback PDF Preflight Checker (interior and cover) (`ars-technis/kdp-pdf-preflight`) Actor

Checks a paperback interior or cover PDF against Amazon KDP's published print rules before you upload: page size for your trim and bleed, page count, gutter and outside margins, embedded fonts, transparency, bookmarks, annotations, 7 pt minimum type, 300 DPI images. One clear report per file.

- **URL**: https://apify.com/ars-technis/kdp-pdf-preflight.md
- **Developed by:** [Ars Technis](https://apify.com/ars-technis) (community)
- **Categories:** Developer tools, Other
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 pdf checkeds

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

## KDP Paperback PDF Preflight Checker

Check a **paperback interior** or **paperback cover** PDF against Amazon KDP's published print rules before you upload it, and get one clear report per file: what passes, what fails, and on which pages.

It is built for self-publishers, puzzle- and activity-book makers, formatting services and AI agents that produce print-ready PDFs. We wrote it because our own books kept meeting these rules, and every check below is one we needed.

### What it checks

Every check names the KDP help page it comes from. Statuses: **pass**, **fail**, **warn** (worth a look) and **info**.

| Check | Rule (KDP Help) |
| --- | --- |
| File size up to 650 MB | Paperback Submission Guidelines (G201857950) |
| Not encrypted or password-protected | G201857950 |
| Page count within KDP's limits for your trim and paper: at least 24 (72 for standard color); at most 828 white / 776 cream / 600 standard color / 828 premium color for trims up to 8 x 10 in, 800/750/600/800 for 8.25 in wide trims, 590/550/600/590 for 8.5 x 8.5 and 8.5 x 11, 780/730/-/590 for A4 (KDP's print-options table as published by third parties, October 2026; for other custom trims only the minimum is checked). An odd page count is counted as the next even number, as KDP adds a blank page. Covers: one page | GVBQ3CMEQW3W2VL6; G201953020 |
| Every page exactly your trim size, or trim + 0.125 in wide and + 0.25 in tall with bleed (the page's crop box, which is what shows, clipped to the media box as the PDF specification says; a page's UserUnit is applied; page boxes, rotation and resources that are malformed on a page are taken from the page tree above it, as Poppler reads them) | GVBQ3CMEQW3W2VL6 |
| Text inside the margins: the inside (gutter) margin for your page count (0.375 in up to 150 pages, 0.5 in up to 300, 0.625 in up to 500, 0.75 in up to 700, 0.875 in up to 828), and 0.25 in top, bottom and outside (0.375 in with bleed). Odd pages are right-hand pages, so their gutter is on the left. | GVBQ3CMEQW3W2VL6 |
| Without bleed, raster image boxes inside the margins (a warning: KDP prints to the edge only from files set up with bleed; an image clipped to a smaller frame can show here) | GVBQ3CMEQW3W2VL6 |
| All fonts embedded | G201857950 |
| No transparency (opacity below 100% where something is painted under it: stroke opacity on a stroke, fill opacity on a fill, text, shading or image, in pages, forms, tiling patterns and Type 3 glyphs; soft masks, images with an alpha channel, blend modes other than Normal); transparency groups alone are a warning | G201857950 |
| No bookmarks; no annotations (comments, links, form fields); layers (optional content) are a warning: flatten them | G201857950 |
| No text smaller than 7 pt (interior): each glyph's height across its baseline on the page, from its font size and its full transformation, so turned, slanted and squashed text is measured as printed; invisible text (render mode 3, as in a scan's OCR layer) is not printed and not measured | G201857950 |
| Images at 300 DPI or more at their printed size on both pixel axes, from the transformation that draws each image, so stretched and turned images are measured as printed (a warning below) | G201857950 |
| Blank pages: at most 4 in a row inside the book and 10 at the end. Each page's crop box is rendered as a press prints it (Poppler, CMYK with overprint, at 36 dpi; very large pages at most 1200 pixels a side); a page with no ink above 2% in any channel is blank. Clipping, shadings, spot colours, image decoding, form boxes and overprint are all followed this way; layers are seen as shown on screen (see the layers warning). Marks smaller than about one pixel at 36 dpi (0.7 mm), such as a very faint hairline, may not register | KDP blank pages (G201834260) |
| Cover: height = trim height + 0.25 in; with `interiorPages` and `paper`, width = 2 x trim width + spine + 0.25 in, the spine being pages x 0.002252 in (white or standard color), 0.0025 in (cream) or 0.002347 in (premium color); without them, the spine width the cover implies | G201953020 |

### What it does not check

- KDP's own previewer and review have the last word; a clean report means these rules pass, not that KDP will accept the book.
- Line weights, grey levels, colour profiles, crop marks drawn as ordinary lines, placeholder text, vector shapes in the margins and file names are not checked.
- Hardcover covers and hardcover-specific limits are not checked: this Actor follows KDP's paperback pages.
- Type size and margins are measured on the text the PDF draws: text hidden by a clipping path is left out (a clipping path is followed as the box around it), but text hidden by text clipping (render mode 7), by a layer that is switched off, or under an opaque shape is still measured. Text and images inside tiling patterns, or drawn by a Type 3 font's glyphs, are checked for embedded fonts and transparency, not for type size, margins or resolution (a Type 3 glyph is measured at its font size, through the font's FontMatrix).
- A page's UserUnit (PDF 1.6) is applied to the page size only; type size, margins and image resolution are measured in the page's own units, as Poppler renders them.
- If a page cannot be read or rendered, the checks that need it are reported as warnings ("Not checked"), not as passes.
- A glyph whose code is a simple font's space (32 or 160) counts as a space, and so does a whitespace character from a CID font; every other glyph counts as text.

### Input

| Field | Default | Notes |
| --- | --- | --- |
| `pdfUrls` | | Public links to the PDFs (up to 50 per run), each up to 650 MB. Leave empty to check a bundled 24-page 6 x 9 in sample interior instead: no per-PDF charge (only Apify's small Actor-start fee applies), and it has one planted mistake (a line in the outside margin on page 5), so you see what a failing check looks like |
| `trimSize` | `6x9` | Width x height in inches, as chosen in KDP, e.g. `5.5x8.5`, `8.5x11` |
| `bleed` | false | On if the interior has bleed |
| `fileType` | `interior` | `interior` or `cover` |
| `paper` | `white` | `white`, `cream`, `standard-color` or `premium-color` |
| `interiorPages` | empty | For a cover: the interior's page count, to check the cover's width exactly |

### Output

One dataset item per file: `file`, `url`, `pages`, `failed` and `warnings` (counts), and `results`, a list of `{check, status, message, rule, pages}` (the pages a problem was found on, up to 50 listed). The `OUTPUT` record says how many files were checked, lists any link that could not be fetched or read, and lists links left unchecked when your maximum cost per run was reached (`notChecked`).

Example (shortened), a 10-page test file with a standard font, small edge text, a 50% grey box, a bookmark, a link and a 30 DPI image:

```
fail page-count       10 pages (KDP supports 24 to 828 for paperbacks; your trim and ink may allow fewer)
fail fonts-embedded   Fonts not embedded: Helvetica
fail transparency     Transparency found: opacity ca=0.5. KDP asks for flattened files.
fail bookmarks        The file has bookmarks (an outline); remove them.
fail annotations      10 page(s) carry annotations (comments, links or form fields).
fail margins-text     Text runs into the margins on 10 page(s): it must keep the inside margin of 0.375 in ...
fail font-size        Text smaller than 7 pt on 10 page(s) (smallest 6.0 pt).
warn image-resolution Images below 300 DPI at their printed size on 10 page(s) (lowest 30 DPI).
```

### Pricing

You pay per file checked (see the pricing tab). A link that cannot be fetched, or a file that is not a PDF, is listed in `OUTPUT.problems` and not charged.

### Privacy

The Actor downloads each PDF from your link into the run's temporary space, checks it, and deletes it; only the report is stored, in your own Apify storage. It is plain Python code (pikepdf and pdfminer.six) plus Poppler's pdftoppm for rendering pages (see CREDITS.md); it calls no AI model and no other service.

# Actor input Schema

## `pdfUrls` (type: `array`):

Public links to the PDFs to check (up to 50 per run). Each must return the PDF file itself, up to 650 MB. Leave empty to see a report on a bundled 24-page sample interior (6 x 9 in, with one planted mistake); that sample check has no per-PDF charge (only Apify's small Actor-start fee applies).

## `trimSize` (type: `string`):

The paperback's trim size, width x height in inches, as chosen in KDP, e.g. 6x9, 5.5x8.5, 8.5x11.

## `bleed` (type: `boolean`):

On if the interior is set up with bleed (pages 0.125 in wider and 0.25 in taller than the trim). Covers always have bleed.

## `paper` (type: `string`):

As chosen in KDP. It sets the page-count limits for your trim and, for a cover, the spine width per page (white and standard color 0.002252 in, cream 0.0025 in, premium color 0.002347 in).

## `interiorPages` (type: `integer`):

For a cover: the interior's page count, so the cover's full width (trim, spine, trim and bleed) is checked exactly. Leave empty to see only the spine width the cover implies.

## `fileType` (type: `string`):

interior = the paperback's pages; cover = the paperback's one-page wrap cover (back, spine, front). Hardcover covers have other dimensions and are not supported.

## Actor input object example

```json
{
  "trimSize": "6x9",
  "bleed": false,
  "paper": "white",
  "fileType": "interior"
}
```

# Actor output Schema

## `reports` (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("ars-technis/kdp-pdf-preflight").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("ars-technis/kdp-pdf-preflight").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 ars-technis/kdp-pdf-preflight --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ars-technis/kdp-pdf-preflight"
        }
    }
}
```

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/S3fHk6nDFAxChbzeC/builds/5meyazsRb2jdhM2Zc/openapi.json
