pdfmux/blog
pdf-extraction

PDF extraction with Gemini: native PDF support, JSON mode, and the limits

TL;DRHow to extract structured data from PDFs with Gemini's native PDF input and response_schema, what it costs, and where a dedicated extractor still wins.

Direct answer: Gemini’s API takes a PDF as direct input — pass the file bytes with mime_type="application/pdf" — and can return extracted fields as JSON when you set response_mime_type to application/json with a response_schema. That gets you a working extraction pipeline in one API call, with no separate OCR step and no manual page-to-image conversion. What it does not get you: per-page confidence, detection of pages the model silently misread, or an offline run, and cost scales per token with no ceiling. For low-volume or ad hoc extraction, it’s the fastest path. For a production pipeline processing thousands of documents, the gaps below start to matter, and a dedicated extractor with page-level confidence — like pdfmux — closes them.


The actual API call

Gemini’s generate_content call accepts a PDF as raw bytes alongside a text instruction. Here’s a minimal working extraction, pulling invoice fields into a typed schema:

import os
from google import genai
from google.genai import types
from pydantic import BaseModel

client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

with open("invoice.pdf", "rb") as f:
    doc_bytes = f.read()

class Invoice(BaseModel):
    invoice_number: str
    vendor_name: str
    total_amount: float
    due_date: str
    line_items: list[str]

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=[
        types.Part.from_bytes(data=doc_bytes, mime_type="application/pdf"),
        "Extract the invoice fields.",
    ],
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=Invoice,
    ),
)

invoice = Invoice.model_validate_json(response.text)
print(invoice)

No separate OCR step, no page-to-image conversion, no prompt-engineering a JSON format by hand — response_schema does the shape enforcement, and Pydantic’s model_validate_json turns the response straight into a typed object. That’s the whole appeal: one call, structured output, zero extraction infrastructure to stand up.

How Gemini actually reads the PDF

There’s no dedicated “PDF parsing” mode distinct from Gemini’s general multimodal input. The API extracts whatever text layer the PDF already has and treats each page as an image for its vision pathway, then reasons over both together. That combination is why it handles a scanned contract with no text layer and a clean digital report through the identical call: for the scanned page, it’s reading pixels; for the digital page, it has actual text to ground on, which tends to produce more reliable output on dense or small-font content than image-only reading would.

This also means quality tracks page complexity the way vision-model reading generally does. A single-column invoice with a normal font extracts cleanly. A rotated scan, a multi-column academic layout, or a table with merged cells is harder — and there’s no signal in the response telling you which case you landed in. The response looks equally confident either way.

What you don’t get

Three gaps show up once you move past a single test document:

No per-page confidence. The API returns your JSON and nothing else. If page 6 of a 15-page report was too blurry for the model to read cleanly and it filled in a plausible-looking number instead of flagging the read as uncertain, nothing in the response tells you that happened. You find out when someone downstream acts on the wrong number.

No silent-drop detection. If the model skips content on a page because your schema didn’t ask for anything specific from it, the response still validates against the schema. There’s no “page 6 was not usable” report the way a dedicated per-page audit produces — we’ve written before about exactly this failure mode showing up weeks after a pipeline ships, and it applies to any single-model extraction call, Gemini included.

No offline option. Every PDF you send goes through Google’s servers. For documents under an NDA, medical records, or anything with a data-residency requirement, that’s not a setting you can toggle off — it’s inherent to calling a hosted API at all.

What it costs at volume

Gemini is billed per token rather than per page, so a page’s cost tracks its density (how much text and detail there is to encode) and the length of the response you ask for, not a flat per-document rate. pdfmux’s internal per-page cost estimate for routing decisions puts Gemini 2.5 Flash and 2.5 Pro (BYOK) at roughly $0.01/page — see the Gemini API pricing page for current official rates before budgeting a large job, since vendor pricing changes over time and this is an internal estimate, not a quoted rate card. There’s no ceiling: a spike in document volume is a proportional spike in token usage, with no local fallback if the API is rate-limited.

Multi-page documents and long context

Gemini’s context window is large enough to take a genuinely long PDF in a single call, which is a real advantage over models with tighter limits — you don’t have to chunk a 40-page contract into sections just to fit it in. The tradeoff is the same one that shows up with any long-context call: more pages competing for the model’s attention means it’s more likely to skim rather than closely read every page, which is the same mechanism behind the silent-drop problem above, not a separate bug. For documents where every page genuinely matters — financial statements, contracts where any clause could be the important one — splitting into smaller chunks and making one call per chunk, then merging results, catches errors a single giant call would miss, at the cost of more API calls.

Two defaults worth setting from the start:

  • Keep the schema’s required fields tight to what genuinely appears on every document. A required field description that doesn’t match what’s actually on the page pushes the model to infer a value rather than signal “not present.”
  • Log the raw response text alongside the parsed object. When a value looks wrong later, the raw response is the only way to tell whether the model misread the page or the schema’s field description was ambiguous.

When the API approach is the right call

None of this makes Gemini the wrong tool. If you’re extracting a few dozen PDFs a week, need zero extraction infrastructure, and the documents are clean enough that occasional silent errors are tolerable — or a human reviews every output — response_schema with a typed Pydantic model is genuinely the fastest path from PDF to structured data. It’s also a strong first pass on documents with irregular layouts a rules-based parser would choke on, since Gemini’s general reasoning handles novelty a fixed layout parser can’t.

Gemini vs Claude vs GPT-4o as the extraction backend

All three take a PDF as multimodal input and none is categorically better at reading a page — the differences show up in cost and specific document types:

Gemini 2.5 Flash/ProClaude (Sonnet/Opus)GPT-4o
Cost per page (BYOK, pdfmux estimate)~$0.01~$0.015~$0.01
StrengthFast, cheap on straightforward scans; long-context single callLong-document reasoning, dense contractsGeneral-purpose, wide language coverage
HandwritingStrongStrongModerate
Structured output mechanismresponse_schema (Pydantic-native)Prompted JSON, no native schema enforcementresponse_format: json_schema with strict mode

None of these numbers argue for one model as your only extraction engine. They argue for picking whichever fits the job after cheaper, deterministic passes have already handled the pages that don’t need a vision model — see PDF extraction with OpenAI and Claude PDF parsing for the same routing argument applied to those backends, and Gemini vs Mistral OCR for how Gemini compares against a narrower, cheaper transcription-only API on the same job.

When you need more than the API gives you

Once volume, cost predictability, data residency, or “did this silently fail” become real requirements, a single model call stops covering them. pdfmux runs locally, scores 0.903 overall (0.911 TEDS on tables) on the opendataloader-bench of 200 real-world PDFs, and reports per-page confidence plus a verify_extraction call that flags pages an extractor silently dropped or mangled — the exact signal missing from a raw Gemini response:

pip install "pdfmux[llm]"
pdfmux convert report.pdf --format json --llm-provider gemini

The two approaches combine well in practice: extract with pdfmux for structure and per-page confidence for free on digital and scanned pages, then route only the pages that fail the confidence audit to Gemini for a second opinion — paying token cost where it’s actually needed instead of on every page of every document.

FAQ

Can Gemini read a PDF directly, or do I need to convert it to images first? Gemini takes a PDF directly as input — pass the raw bytes with mime_type set to application/pdf and the API handles rendering internally. You don’t need to convert pages to images yourself, and Gemini uses both the PDF’s text layer where one exists and its vision understanding of the rendered page, so it handles scanned and digital PDFs through the same call.

Does Gemini guarantee its JSON output matches my schema? Setting response_mime_type to application/json with a response_schema constrains the model to return valid JSON matching that schema’s shape. It does not guarantee the values are correct — a schema-valid response can still contain a hallucinated number in a properly typed field, the same limitation every structured-output API has.

What does PDF extraction with Gemini cost at scale? Gemini is billed per token, not per page, so cost depends on page density and response length rather than a flat per-page rate. pdfmux’s internal routing estimate for Gemini 2.5 Flash and 2.5 Pro as BYOK backends is roughly $0.01 per page; see the Gemini API pricing page for current official rates before budgeting a large job.

Frequently asked questions

Can Gemini read a PDF directly, or do I need to convert it to images first?

Gemini takes a PDF directly as input — pass the raw bytes with mime_type set to application/pdf and the API handles rendering internally. You don't need to convert pages to images yourself, and Gemini uses both the PDF's text layer where one exists and its vision understanding of the rendered page, so it handles scanned and digital PDFs through the same call.

Does Gemini guarantee its JSON output matches my schema?

Setting response_mime_type to application/json with a response_schema constrains the model to return valid JSON matching that schema's shape. It does not guarantee the values are correct — a schema-valid response can still contain a hallucinated number in a properly typed field, the same limitation every structured-output API has.

What does PDF extraction with Gemini cost at scale?

Gemini is billed per token, not per page, so cost depends on page density and response length rather than a flat per-page rate. pdfmux's internal routing estimate for Gemini 2.5 Flash and 2.5 Pro as BYOK backends is roughly $0.01 per page; see the Gemini API pricing page for current official rates before budgeting a large job.