Repository Public
1# Document understanding23> [!NOTE]4> **Note** : This version of the page covers the new [Interactions API](https://ai.google.dev/gemini-api/docs/interactions/interactions-overview), which is currently in Beta. 5> For stable production deployments, we recommend you continue to use the `generateContent` API. You can use the toggle on this page to switch between the versions.67Gemini models can process documents in PDF format, using native8vision to understand entire document contexts. This goes beyond9just text extraction, allowing Gemini to:1011- Analyze and interpret content, including text, images, diagrams, charts, and tables, even in long documents up to 1000 pages.12- Extract information into [structured output](https://ai.google.dev/gemini-api/docs/interactions/structured-output) formats.13- Summarize and answer questions based on both the visual and textual elements in a document.14- Transcribe document content (e.g. to HTML), preserving layouts and formatting, for use in downstream applications.1516You can also pass non-PDF documents in the same way but Gemini will see them17as normal text which will eliminate context like charts or formatting.1819## Passing PDF data inline2021You can pass PDF data inline in the request. This is best22suited for smaller documents or temporary processing where you don't need to23reference the file in subsequent requests. We recommend using the24[Files API](https://ai.google.dev/gemini-api/docs/interactions/document-processing#large-pdfs)25for larger documents that you need to refer to in multi-turn interactions to26improve request latency and reduce bandwidth usage.2728The following example shows you how to pass PDF data inline:2930### Python3132 from google import genai33 import base643435 client = genai.Client()3637 with open('path/to/document.pdf', 'rb') as f:38 pdf_bytes = f.read()3940 interaction = client.interactions.create(41 model="gemini-3.5-flash",42 input=[43 {44 "type": "document",45 "data": base64.b64encode(pdf_bytes).decode('utf-8'),46 "mime_type": "application/pdf"47 },48 {"type": "text", "text": "Summarize this document"}49 ]50 )5152 print(interaction.output_text)5354### JavaScript5556 import { GoogleGenAI } from "@google/genai";57 import * as fs from "node:fs";5859 const ai = new GoogleGenAI({});6061 async function main() {62 const pdfData = fs.readFileSync("path/to/document.pdf", {63 encoding: "base64"64 });6566 const interaction = await ai.interactions.create({67 model: "gemini-3.5-flash",68 input: [69 { type: "text", text: "Summarize this document" },70 {71 type: "document",72 data: pdfData,73 mime_type: "application/pdf"74 }75 ]76 });77 console.log(interaction.output_text);78 }7980 main();8182### REST8384 PDF_PATH="path/to/document.pdf"8586 if [[ "$(base64 --version 2>&1)" = *"FreeBSD"* ]]; then87 B64FLAGS="--input"88 else89 B64FLAGS="-w0"90 fi9192 curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \93 -H "x-goog-api-key: $GEMINI_API_KEY" \94 -H 'Content-Type: application/json' \95 -H "Api-Revision: 2026-05-20" \96 -d '{97 "model": "gemini-3.5-flash",98 "input": [99 {100 "type": "document",101 "data": "'$(base64 $B64FLAGS $PDF_PATH)'",102 "mime_type": "application/pdf"103 },104 {"type": "text", "text": "Summarize this document"}105 ]106 }'107108You can also upload a local PDF file for processing:109110### Python111112 from google import genai113114 client = genai.Client()115116 uploaded_file = client.files.upload(file="file.pdf")117118 interaction = client.interactions.create(119 model="gemini-3.5-flash",120 input=[121 {"type": "document", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type},122 {"type": "text", "text": "Summarize this document"}123 ]124 )125 print(interaction.output_text)126127### JavaScript128129 import { GoogleGenAI } from "@google/genai";130131 const ai = new GoogleGenAI({});132133 async function main() {134 const uploadedFile = await ai.files.upload({135 file: "file.pdf",136 config: { mime_type: "application/pdf" }137 });138139 const interaction = await ai.interactions.create({140 model: "gemini-3.5-flash",141 input: [142 { type: "text", text: "Summarize this document" },143 {144 type: "document",145 uri: uploadedFile.uri,146 mime_type: uploadedFile.mime_type147 }148 ]149 });150 console.log(interaction.output_text);151 }152153 main();154155## Uploading PDFs using the Files API156157We recommend you use Files API for larger files or when you intend to reuse a158document across multiple requests. This improves request latency and reduces159bandwidth usage by decoupling the file upload from the model requests.160161> [!NOTE]162> **Note:** The Files API is available at no cost in all regions where the Gemini API is available. Uploaded files are stored for 48 hours.163164### Large PDFs from URLs165166Use the File API to simplify uploading and processing large PDF files from URLs:167168### Python169170 from google import genai171 import io172 import httpx173174 client = genai.Client()175176 long_context_pdf_path = "https://arxiv.org/pdf/2312.11805"177178 doc_io = io.BytesIO(httpx.get(long_context_pdf_path).content)179180 sample_doc = client.files.upload(181 file=doc_io,182 config=dict(183 mime_type='application/pdf')184 )185186 prompt = "Summarize this document"187188 interaction = client.interactions.create(189 model="gemini-3.5-flash",190 input=[191 {"type": "document", "uri": sample_doc.uri, "mime_type": sample_doc.mime_type},192 {"type": "text", "text": prompt}193 ]194 )195 print(interaction.output_text)196197### JavaScript198199 import { GoogleGenAI } from "@google/genai";200201 const ai = new GoogleGenAI({});202203 async function main() {204205 const pdfBuffer = await fetch("https://arxiv.org/pdf/2312.11805")206 .then((response) => response.arrayBuffer());207208 const fileBlob = new Blob([pdfBuffer], { type: 'application/pdf' });209210 const file = await ai.files.upload({211 file: fileBlob,212 config: {213 displayName: 'A17_FlightPlan.pdf',214 },215 });216217 let getFile = await ai.files.get({ name: file.name });218 while (getFile.state === 'PROCESSING') {219 getFile = await ai.files.get({ name: file.name });220 console.log(`current file status: ${getFile.state}`);221 console.log('File is still processing, retrying in 5 seconds');222223 await new Promise((resolve) => {224 setTimeout(resolve, 5000);225 });226 }227 if (file.state === 'FAILED') {228 throw new Error('File processing failed.');229 }230231 const interaction = await ai.interactions.create({232 model: 'gemini-3.5-flash',233 input: [234 { type: "document", uri: file.uri, mime_type: file.mime_type },235 { type: "text", text: "Summarize this document" }236 ],237 });238239 console.log(interaction.output_text);240241 }242243 main();244245### REST246247 PDF_PATH="https://arxiv.org/pdf/2312.11805"248 DISPLAY_NAME="Gemini_paper"249 PROMPT="Summarize this document"250251 # Download the PDF from the provided URL252 wget -O "${DISPLAY_NAME}.pdf" "${PDF_PATH}"253254 MIME_TYPE=$(file -b --mime-type "${DISPLAY_NAME}.pdf")255 NUM_BYTES=$(wc -c < "${DISPLAY_NAME}.pdf")256257 echo "MIME_TYPE: ${MIME_TYPE}"258 echo "NUM_BYTES: ${NUM_BYTES}"259260 tmp_header_file=upload-header.tmp261262 # Initial resumable request defining metadata.263 # The upload url is in the response headers dump them to a file.264 curl "https://generativelanguage.googleapis.com/upload/v1beta/files?key=${GEMINI_API_KEY}" \265 -D upload-header.tmp \266 -H "X-Goog-Upload-Protocol: resumable" \267 -H "X-Goog-Upload-Command: start" \268 -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \269 -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \270 -H "Content-Type: application/json" \271 -d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null272273 upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")274 rm "${tmp_header_file}"275276 # Upload the actual bytes.277 curl "${upload_url}" \278 -H "Content-Length: ${NUM_BYTES}" \279 -H "X-Goog-Upload-Offset: 0" \280 -H "X-Goog-Upload-Command: upload, finalize" \281 --data-binary "@${DISPLAY_NAME}.pdf" 2> /dev/null > file_info.json282283 file_uri=$(jq -r ".file.uri" file_info.json)284 echo "file_uri: ${file_uri}"285286 # Create payload JSON file for safety287 cat << EOF > payload.json288 {289 "model": "gemini-3.5-flash",290 "input": [291 {"type": "text", "text": "${PROMPT}"},292 {"type": "document", "uri": "${file_uri}", "mime_type": "application/pdf"}293 ]294 }295 EOF296297 # Now create an interaction using that file298 curl "https://generativelanguage.googleapis.com/v1beta/interactions" \299 -H "x-goog-api-key: $GEMINI_API_KEY" \300 -H 'Content-Type: application/json' \301 -H "Api-Revision: 2026-05-20" \302 -X POST \303 -d @payload.json 2> /dev/null > response.json304305 cat response.json306 echo307308 jq ".steps[-1].content[0].text" response.json309310 # Clean up311 rm "${DISPLAY_NAME}.pdf"312 rm payload.json313314### Large PDFs stored locally315316### Python317318 from google import genai319 import pathlib320321 client = genai.Client()322323 file_path = pathlib.Path('large_file.pdf')324 sample_file = client.files.upload(325 file=file_path,326 )327328 interaction = client.interactions.create(329 model="gemini-3.5-flash",330 input=[331 {"type": "document", "uri": sample_file.uri, "mime_type": sample_file.mime_type},332 {"type": "text", "text": "Summarize this document"}333 ]334 )335 print(interaction.output_text)336337### JavaScript338339 import { GoogleGenAI } from "@google/genai";340341 const ai = new GoogleGenAI({});342343 async function main() {344 const file = await ai.files.upload({345 file: 'path-to-localfile.pdf',346 config: {347 displayName: 'A17_FlightPlan.pdf',348 },349 });350351 let getFile = await ai.files.get({ name: file.name });352 while (getFile.state === 'PROCESSING') {353 getFile = await ai.files.get({ name: file.name });354 console.log(`current file status: ${getFile.state}`);355 console.log('File is still processing, retrying in 5 seconds');356357 await new Promise((resolve) => {358 setTimeout(resolve, 5000);359 });360 }361 if (file.state === 'FAILED') {362 throw new Error('File processing failed.');363 }364365 const interaction = await ai.interactions.create({366 model: 'gemini-3.5-flash',367 input: [368 { type: "document", uri: file.uri, mime_type: file.mime_type },369 { type: "text", text: "Summarize this document" }370 ],371 });372373 console.log(interaction.output_text);374375 }376377 main();378379### REST380381 PDF_PATH="path/to/large_file.pdf"382 NUM_BYTES=$(wc -c < "${PDF_PATH}")383 DISPLAY_NAME=TEXT384 tmp_header_file=upload-header.tmp385386 # Initial resumable request defining metadata.387 # The upload url is in the response headers dump them to a file.388 curl "https://generativelanguage.googleapis.com/upload/v1beta/files?key=${GEMINI_API_KEY}" \389 -D upload-header.tmp \390 -H "X-Goog-Upload-Protocol: resumable" \391 -H "X-Goog-Upload-Command: start" \392 -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \393 -H "X-Goog-Upload-Header-Content-Type: application/pdf" \394 -H "Content-Type: application/json" \395 -d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null396397 upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")398 rm "${tmp_header_file}"399400 # Upload the actual bytes.401 curl "${upload_url}" \402 -H "Content-Length: ${NUM_BYTES}" \403 -H "X-Goog-Upload-Offset: 0" \404 -H "X-Goog-Upload-Command: upload, finalize" \405 --data-binary "@${PDF_PATH}" 2> /dev/null > file_info.json406407 file_uri=$(jq ".file.uri" file_info.json)408 echo file_uri=$file_uri409410 # Now create an interaction using that file411 curl "https://generativelanguage.googleapis.com/v1beta/interactions" \412 -H "x-goog-api-key: $GEMINI_API_KEY" \413 -H 'Content-Type: application/json' \414 -H "Api-Revision: 2026-05-20" \415 -X POST \416 -d '{417 "model": "gemini-3.5-flash",418 "input": [419 {"type": "document", "uri": '$file_uri', "mime_type": "application/pdf"},420 {"type": "text", "text": "Can you add a few more lines to this poem?"}421 ]422 }' 2> /dev/null > response.json423424 cat response.json425 echo426427 jq ".steps[-1].content[0].text" response.json428429You can verify the API successfully stored the uploaded file and get its430metadata by calling [`files.get`](https://ai.google.dev/api/rest/v1beta/files/get). Only the `name`431(and by extension, the `uri`) are unique.432433### Python434435 from google import genai436 import pathlib437438 client = genai.Client()439440 fpath = pathlib.Path('example.pdf')441 fpath.write_text('hello')442443 file = client.files.upload(file='example.pdf')444445 file_info = client.files.get(name=file.name)446 print(file_info.model_dump_json(indent=4))447448### REST449450 name=$(jq -r ".file.name" file_info.json)451 # Get the file of interest to check state452 curl "https://generativelanguage.googleapis.com/v1beta/$name?key=$GEMINI_API_KEY" > file_info.json453 # Print some information about the file you got454 name=$(jq -r ".name" file_info.json)455 echo name=$name456 file_uri=$(jq -r ".uri" file_info.json)457 echo file_uri=$file_uri458459## Passing multiple PDFs460461The Gemini API is capable of processing multiple PDF documents (up to 1000 pages)462in a single request, as long as the combined size of the documents and the text463prompt stays within the model's context window.464465### Python466467 from google import genai468 import io469 import httpx470471 client = genai.Client()472473 doc_url_1 = "https://arxiv.org/pdf/2312.11805"474 doc_url_2 = "https://arxiv.org/pdf/2403.05530"475476 doc_data_1 = io.BytesIO(httpx.get(doc_url_1).content)477 doc_data_2 = io.BytesIO(httpx.get(doc_url_2).content)478479 sample_pdf_1 = client.files.upload(480 file=doc_data_1,481 config=dict(mime_type='application/pdf')482 )483 sample_pdf_2 = client.files.upload(484 file=doc_data_2,485 config=dict(mime_type='application/pdf')486 )487488 prompt = "What is the difference between each of the main benchmarks between these two papers? Output these in a table."489490 interaction = client.interactions.create(491 model="gemini-3.5-flash",492 input=[493 {"type": "document", "uri": sample_pdf_1.uri, "mime_type": sample_pdf_1.mime_type},494 {"type": "document", "uri": sample_pdf_2.uri, "mime_type": sample_pdf_2.mime_type},495 {"type": "text", "text": prompt}496 ]497 )498499 print(interaction.output_text)500501### JavaScript502503 import { GoogleGenAI } from "@google/genai";504505 const ai = new GoogleGenAI({});506507 async function uploadRemotePDF(url, displayName) {508 const pdfBuffer = await fetch(url)509 .then((response) => response.arrayBuffer());510511 const fileBlob = new Blob([pdfBuffer], { type: 'application/pdf' });512513 const file = await ai.files.upload({514 file: fileBlob,515 config: {516 displayName: displayName,517 },518 });519520 let getFile = await ai.files.get({ name: file.name });521 while (getFile.state === 'PROCESSING') {522 getFile = await ai.files.get({ name: file.name });523 console.log(`current file status: ${getFile.state}`);524 console.log('File is still processing, retrying in 5 seconds');525526 await new Promise((resolve) => {527 setTimeout(resolve, 5000);528 });529 }530 if (file.state === 'FAILED') {531 throw new Error('File processing failed.');532 }533534 return file;535 }536537 async function main() {538 const file1 = await uploadRemotePDF("https://arxiv.org/pdf/2312.11805", "PDF 1");539 const file2 = await uploadRemotePDF("https://arxiv.org/pdf/2403.05530", "PDF 2");540541 const interaction = await ai.interactions.create({542 model: 'gemini-3.5-flash',543 input: [544 { type: "document", uri: file1.uri, mime_type: file1.mime_type },545 { type: "document", uri: file2.uri, mime_type: file2.mime_type },546 { type: "text", text: "What is the difference between each of the main benchmarks between these two papers? Output these in a table." }547 ],548 });549550 console.log(interaction.output_text);551 }552553 main();554555### REST556557 DOC_URL_1="https://arxiv.org/pdf/2312.11805"558 DOC_URL_2="https://arxiv.org/pdf/2403.05530"559 DISPLAY_NAME_1="Gemini_paper"560 DISPLAY_NAME_2="Gemini_1.5_paper"561 PROMPT="What is the difference between each of the main benchmarks between these two papers? Output these in a table."562563 # Function to download and upload a PDF564 upload_pdf() {565 local doc_url="$1"566 local display_name="$2"567568 echo "Downloading ${display_name} from ${doc_url}..." >&2569 # Download the PDF570 wget -O "${display_name}.pdf" "${doc_url}" 2> /dev/null571572 local MIME_TYPE=$(file -b --mime-type "${display_name}.pdf")573 local NUM_BYTES=$(wc -c < "${display_name}.pdf")574575 echo "MIME_TYPE: ${MIME_TYPE}" >&2576 echo "NUM_BYTES: ${NUM_BYTES}" >&2577578 local tmp_header_file="upload-header-${display_name}.tmp"579580 # Initial resumable request581 # Using GEMINI_API_KEY instead of GOOGLE_API_KEY582 curl "https://generativelanguage.googleapis.com/upload/v1beta/files?key=${GEMINI_API_KEY}" \583 -D "${tmp_header_file}" \584 -H "X-Goog-Upload-Protocol: resumable" \585 -H "X-Goog-Upload-Command: start" \586 -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \587 -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \588 -H "Content-Type: application/json" \589 -d "{'file': {'display_name': '${display_name}'}}" 2> /dev/null590591 local upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")592 rm "${tmp_header_file}"593594 echo "Upload URL for ${display_name}: ${upload_url}" >&2595596 # Upload the PDF597 curl "${upload_url}" \598 -H "Content-Length: ${NUM_BYTES}" \599 -H "X-Goog-Upload-Offset: 0" \600 -H "X-Goog-Upload-Command: upload, finalize" \601 --data-binary "@${display_name}.pdf" 2> /dev/null > "file_info_${display_name}.json"602603 local file_uri=$(jq -r ".file.uri" "file_info_${display_name}.json")604 echo "file_uri for ${display_name}: ${file_uri}" >&2605606 # Clean up the downloaded PDF607 rm "${display_name}.pdf"608609 echo "${file_uri}"610 }611612 # Upload the first PDF613 file_uri_1=$(upload_pdf "${DOC_URL_1}" "${DISPLAY_NAME_1}")614615 # Upload the second PDF616 file_uri_2=$(upload_pdf "${DOC_URL_2}" "${DISPLAY_NAME_2}")617618 # Create payload JSON file for safety619 cat << EOF > payload_multi.json620 {621 "model": "gemini-3.5-flash",622 "input": [623 {"type": "document", "uri": "${file_uri_1}", "mime_type": "application/pdf"},624 {"type": "document", "uri": "${file_uri_2}", "mime_type": "application/pdf"},625 {"type": "text", "text": "${PROMPT}"}626 ]627 }628 EOF629630 # Now create an interaction using both files631 # Using GEMINI_API_KEY instead of GOOGLE_API_KEY632 curl "https://generativelanguage.googleapis.com/v1beta/interactions" \633 -H "x-goog-api-key: $GEMINI_API_KEY" \634 -H 'Content-Type: application/json' \635 -H "Api-Revision: 2026-05-20" \636 -X POST \637 -d @payload_multi.json 2> /dev/null > response.json638639 cat response.json640 echo641642 jq ".steps[-1].content[0].text" response.json643644 # Clean up645 rm payload_multi.json646 rm "file_info_${DISPLAY_NAME_1}.json"647 rm "file_info_${DISPLAY_NAME_2}.json"648649## Technical details650651Gemini supports PDF files up to 50MB or 1000 pages. This limit applies652to both inline data and Files API uploads. Each document page is equivalent to 258653tokens.654655While there are no specific limits to the number of pixels in a document besides656the model's [context window](https://ai.google.dev/gemini-api/docs/long-context), larger pages are657scaled down to a maximum resolution of 3072 x 3072 while preserving their original658aspect ratio, while smaller pages are scaled up to 768 x 768 pixels. There is no659cost reduction for pages at lower sizes, other than bandwidth, or performance660improvement for pages at higher resolution.661662### Gemini 3 models663664Gemini 3 introduces granular control over multimodal vision processing with the665`media_resolution` parameter. You can now set the resolution to low, medium, or666high per individual media part. With this addition, the processing of PDF667documents has been updated:6686691. **Native text inclusion:** Text natively embedded in the PDF is extracted and provided to the model.6702. **Billing \& token reporting:**671 - You are **not charged** for tokens originating from the extracted **native text** in PDFs.672 - In the `usage_metadata` section of the API response, tokens generated from processing PDF pages (as images) are now counted under the `IMAGE` modality, not a separate `DOCUMENT` modality as in some earlier versions.673674### Document types675676Technically, you can pass other MIME types for document understanding, like677TXT, Markdown, HTML, XML, etc. However, document vision ***only meaningfully678understands PDFs***. Other types will be extracted as pure text, and the model679won't be able to interpret what we see in the rendering of those files. Any680file-type specifics like charts, diagrams, HTML tags, Markdown formatting, etc.,681will be lost.682683To learn about other file input methods, see the684[File input methods](https://ai.google.dev/gemini-api/docs/interactions/file-input-methods) guide.685686### Best practices687688For best results:689690- Rotate pages to the correct orientation before uploading.691- Avoid blurry pages.692- If using a single page, place the text prompt after the page.693694## What's next695696To learn more, see the following resources:697698- [File prompting strategies](https://ai.google.dev/gemini-api/docs/interactions/files#prompt-guide): The Gemini API supports prompting with text, image, audio, and video data, also known as multimodal prompting.699- [System instructions](https://ai.google.dev/gemini-api/docs/interactions/text-generation#system-instructions): System instructions let you steer the behavior of the model based on your specific needs and use cases.