# PDF & Image AI Extractor: OCR to Markdown, Text & JSON (Gemini) (`itzcloud/pdf-ai-extractor`) Actor

Turn PDFs, scans and photos into Markdown with real tables, plain text or structured JSON (invoices, receipts, CVs, bank statements or your own fields) with Google Gemini. Digital pages are read locally at a fraction of the price; only scans use AI. Pay only for pages that return content.

- **URL**: https://apify.com/itzcloud/pdf-ai-extractor.md
- **Developed by:** [Juan Orjuela](https://apify.com/itzcloud) (community)
- **Categories:** AI, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 ai pages

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## PDF & Image AI Extractor: OCR to Markdown, Text & JSON

Turn PDFs, scanned documents and phone photos into **clean Markdown with real tables**, **plain text** or **structured JSON**, powered by Google Gemini.

- **Scanned and image-only PDFs**: full OCR, including handwriting, stamps and small print.
- **Tables stay tables**: every table becomes a Markdown table, ready for RAG pipelines and LLMs.
- **Structured extraction**: invoices, receipts, resumes/CVs, bank statements, contracts, or **your own fields**.
- **You only pay AI prices where AI is needed.** In Auto mode, pages that already have a text layer are read locally at the cheap text-page price; only scanned pages go to the AI.
- **Bring your own Gemini key** and AI pages drop to the BYOK price.

### What you get

One row per document:

| Field | Description |
|---|---|
| `url`, `fileName`, `fileType`, `sizeBytes` | The source file |
| `pageCount`, `pagesProcessed` | Pages in the file and pages processed |
| `textLayerPages`, `aiPages`, `failedPages` | How each page was read |
| `content` | The whole document as Markdown or plain text |
| `pages` | Per-page results: `page`, `method` (`text-layer`, `ai`, `empty`, `failed`), `content` |
| `data` | Structured JSON output (when Output = Structured JSON) |
| `error` | Why a document or some pages could not be read (those are not charged) |

The dataset has three views: **Documents**, **Extracted fields** and **One row per page** (handy for RAG chunking with page citations).

#### Example: Markdown output

```json
{
  "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf",
  "fileName": "fw9.pdf",
  "pageCount": 6,
  "textLayerPages": 6,
  "aiPages": 0,
  "content": "Form W-9(Rev. March 2024)\nRequest for Taxpayer\nIdentification Number and Certification\nDepartment of the Treasury...",
  "pages": [{ "page": 1, "method": "text-layer", "content": "Form W-9(Rev. March 2024)..." }]
}
```

#### Example: invoice to JSON

```json
{
  "url": "https://example.com/invoice-1043.pdf",
  "pageCount": 2,
  "data": {
    "invoiceNumber": "1043",
    "issueDate": "2026-09-30",
    "currency": "USD",
    "seller": { "name": "Northwind Ltd", "taxId": "US-12-3456789" },
    "lineItems": [{ "description": "Consulting, September", "quantity": 10, "unitPrice": 120, "amount": 1200 }],
    "taxTotal": 96,
    "total": 1296
  }
}
```

### How to use it

1. Paste direct links to your files in **PDF or image URLs** (PDF, PNG, JPEG, WebP, HEIC; up to 50 MB each). Google Drive and Dropbox share links work if the file is shared with "anyone with the link".
2. Choose the **Output**: Markdown, Plain text or Structured JSON.
3. For Structured JSON, pick a **Document type** or define **Custom fields** like `total (number): grand total including tax`.
4. Run it. Results stream into the dataset as each document finishes.

**Engines:**

| Engine | What it does | Best for |
|---|---|---|
| **Auto** (default) | Digital pages read locally; scanned pages (including scans with an old, error-prone OCR layer) by AI | Mixed batches, lowest cost |
| **AI on every page** | Every page through Gemini | Best layout and table fidelity |
| **Text layer only** | No AI at all | Digital PDFs where you just need the text |

### Pricing

Pay per event: you are charged only for pages that return content. Failed pages, empty pages and documents that cannot be opened are free.

| Event | When | Price (free plan) |
|---|---|--:|
| **AI page** | A page or image read by Gemini using the Actor's AI | $10 per 1,000 pages |
| **Text-layer page** | A page read from the PDF's own text layer (Auto and Text-layer modes) | $1 per 1,000 pages |
| **AI page (your key)** | A page read by Gemini with your own API key; Google bills you for the tokens | $2 per 1,000 pages |

Paid Apify plans get up to 30% off (see the **Pricing** tab). A 10-page digital PDF in Auto mode costs about $0.01; a 10-page scan costs $0.10. The maximum cost per run you set is always respected: the Actor stops cleanly and keeps everything already processed.

### Integrations

Works anywhere Apify does: the API, Make, Zapier, n8n, Google Sheets, webhooks, and AI agents through the Apify MCP server. A typical flow: new invoice email → save the attachment → run this Actor with the Invoice preset → append the JSON to a spreadsheet.

### FAQ

**Is my data used to train models?** Documents are sent to Google's paid Gemini API, which does not use your content to improve Google's products. Files are processed in memory and not stored by this Actor. If you use your own key on Google's free tier, Google's free-tier terms apply.

**What about password-protected PDFs?** PDFs that only restrict printing or copying work. PDFs that need a password to open cannot be read.

**Very long documents?** Up to 1,000 pages per PDF. Use *Max pages per document* to process only the first pages.

**Which languages?** Any language Gemini reads, including mixed-language documents. The text is never translated.

**Can I ask for something specific?** Use *Extra instructions*, for example "amounts are in Colombian pesos" or "ignore the cover page".

# Actor input Schema

## `startUrls` (type: `array`):

Direct links to PDF, PNG, JPEG, WebP or HEIC files (up to 50 MB each). Google Drive and Dropbox share links are converted automatically; the file must be shared as "anyone with the link".

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

<b>Markdown</b>: headings, lists and tables, ready for RAG and LLMs. <b>Plain text</b>: reading order without markup. <b>Structured JSON</b>: one object per document with the fields you choose (invoices, receipts, CVs, bank statements, contracts or your own fields).

## `engine` (type: `string`):

<b>Auto</b> (recommended): pages with a real text layer are read locally (text-page price) and only scanned or image-only pages go to Gemini (AI-page price). <b>AI on every page</b>: best layout and table fidelity. <b>Text layer only</b>: no AI; scanned pages come back empty and are not charged. Structured JSON always uses AI.

## `extractionPreset` (type: `string`):

Fields to extract when the output is Structured JSON. Choose <b>Custom</b> to define your own below.

## `fields` (type: `array`):

One per line, as <code>name (type): description</code>. Types: string, number, integer, boolean, date, list. Example: <code>total (number): grand total including tax</code>.

## `jsonSchema` (type: `object`):

Instead of the field list, paste a full JSON Schema (type, properties, items, enum, description). Takes priority over Custom fields.

## `instructions` (type: `string`):

Plain-language hints for the AI, e.g. "Amounts are in Colombian pesos" or "Ignore the cover page".

## `maxPagesPerDocument` (type: `integer`):

Process only the first N pages of each PDF. 0 = all pages (up to 1,000).

## `includePages` (type: `boolean`):

Adds a <code>pages</code> array with each page's content and how it was read (text layer or AI). Useful for citations and RAG chunks.

## `maxDocuments` (type: `integer`):

Stop after this many documents. 0 = no limit.

## `model` (type: `string`):

Flash-Lite is fast and accurate for transcription. Pick Flash for hard handwriting or very dense tables. The price per page is the same.

## `geminiApiKey` (type: `string`):

Bring your own key from <a href='https://aistudio.google.com/apikey' target='_blank'>Google AI Studio</a> and AI pages are charged at the much lower bring-your-own-key price; Google bills you directly for tokens. Leave empty to use ours.

## `maxConcurrency` (type: `integer`):

Leave empty for automatic (based on memory).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
    }
  ],
  "outputFormat": "markdown",
  "engine": "auto",
  "extractionPreset": "invoice",
  "fields": [
    "vendor: company that issued the document",
    "total (number): grand total including tax",
    "date (date): issue date"
  ],
  "maxPagesPerDocument": 0,
  "includePages": true,
  "maxDocuments": 0,
  "model": "gemini-3.1-flash-lite"
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `extracted` (type: `string`):

No description

## `pages` (type: `string`):

No description

## `allFields` (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 = {
    "startUrls": [
        {
            "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
        }
    ],
    "fields": [
        "vendor: company that issued the document",
        "total (number): grand total including tax",
        "date (date): issue date"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("itzcloud/pdf-ai-extractor").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 = {
    "startUrls": [{ "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf" }],
    "fields": [
        "vendor: company that issued the document",
        "total (number): grand total including tax",
        "date (date): issue date",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("itzcloud/pdf-ai-extractor").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 '{
  "startUrls": [
    {
      "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
    }
  ],
  "fields": [
    "vendor: company that issued the document",
    "total (number): grand total including tax",
    "date (date): issue date"
  ]
}' |
apify call itzcloud/pdf-ai-extractor --silent --output-dataset

```

## MCP server setup

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

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/35jegsvE0A6LzkiSn/builds/ynizctiIMDKdj1nPp/openapi.json
