OCR and Document Analysis Prompts
Extracting text, tables, and structure from document images.
OCR and Document Analysis Prompts is a free AI Prompt Engineering lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the AI Prompt Engineering learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
LLMs as Document Readers
OCR (Optical Character Recognition) traditionally required specialized software to extract text from images. Vision LLMs can now read text from images and also understand the content — not just extract characters, but parse structure, tables, handwriting, and context.
Common document analysis tasks:
- Extracting text from scanned documents
- Reading receipts, invoices, and forms
- Parsing tables and charts
- Transcribing handwritten notes
- Reading printed labels and signs
Basic Text Extraction Prompt
For simple text extraction from a document image:
import anthropic, base64
client = anthropic.Anthropic(api_key='YOUR_API_KEY')
def extract_text(image_path, extraction_prompt):
with open(image_path, 'rb') as f:
img_b64 = base64.standard_b64encode(f.read()).decode('utf-8')
r = client.messages.create(
model='claude-opus-4-5', max_tokens=1000,
messages=[{'role': 'user', 'content': [
{'type': 'image', 'source': {'type': 'base64', 'media_type': 'image/jpeg', 'data': img_b64}},
{'type': 'text', 'text': extraction_prompt}
]}]
)
return r.content[0].text
# Basic extraction
basic_prompt = 'Extract all text from this document image exactly as it appears. Preserve line breaks.'
# Structure-preserving extraction
structured_prompt = 'Extract all text from this document image. Preserve: paragraph structure, line breaks, and any visible formatting. Do not add any text not present in the image.'
print('Text extraction functions defined.')Table Structure Preservation
When a document contains a table, extracting it as flat text loses the structure. Use prompts that explicitly preserve table format:
table_prompt = '''
Extract all text from this document image.
If the document contains any tables, preserve the table structure using markdown table format:
| Column 1 | Column 2 | Column 3 |
|----------|----------|----------|
| Value | Value | Value |
For any text outside tables, use plain text preserving paragraph structure.
Do not invent or infer any data not visible in the image.
'''
# For structured output:
table_json_prompt = '''
Extract the table from this image.
Return JSON:
{
"headers": ["column name"],
"rows": [["cell value", "cell value"]],
"caption": "table caption if present or null"
}
If a cell is empty or illegible, use null.
'''
print('Table extraction prompts defined.')Receipt Itemization
Receipts have a specific structure — header (merchant), line items, and totals. A receipt-specific prompt extracts this structure reliably:
import json
receipt_prompt = '''
Extract all information from this receipt image.
Return JSON:
{
"merchant": {
"name": str,
"address": str or null,
"phone": str or null
},
"transaction": {
"date": "YYYY-MM-DD or as written",
"time": "HH:MM or as written or null",
"receipt_number": str or null,
"payment_method": str or null
},
"items": [
{"description": str, "quantity": number or null, "unit_price": number or null, "total": number}
],
"subtotal": number or null,
"tax": number or null,
"tip": number or null,
"total": number,
"currency": "3-letter ISO code"
}
For any field not visible, use null. For numbers, use numeric type (not string).
'''
def extract_receipt(image_path):
text = extract_text(image_path, receipt_prompt)
return json.loads(text)
print('Receipt extraction function defined.')Handwritten Note Transcription
Transcribing handwritten content requires prompts that acknowledge the challenges — illegible words, crossed-out text, abbreviations:
handwriting_prompt = '''
Transcribe the handwritten text in this image as accurately as possible.
Handling rules:
- If a word is illegible, write [ILLEGIBLE]
- If a word is partially legible, write [PARTIAL: best_guess]
- If text is crossed out, include it with strikethrough notation: ~~crossed out text~~
- Preserve line breaks as they appear
- If there are arrows, circles, or annotations, note them in brackets: [arrow pointing right]
- Do not correct spelling or grammar
After transcription, estimate overall legibility: high (>90% readable) | medium (70-90%) | low (<70%)
Format:
TRANSCRIPTION:
[transcribed text here]
LEGIBILITY: [rating]
'''
print(handwriting_prompt)Form Field Extraction
Printed forms have labeled fields and entered values. A form extraction prompt maps labels to values:
form_prompt = '''
Extract all form fields and their values from this document image.
For each field:
- Field label: the printed label (e.g., "First Name:", "Date of Birth:")
- Field value: the filled-in value (handwritten or typed)
- Filled: whether the field has been filled in (true/false)
Return JSON:
{
"form_title": str or null,
"fields": [
{
"label": str,
"value": str or null,
"filled": true | false
}
],
"signature_present": true | false,
"date_signed": str or null
}
If the value is illegible, use "[ILLEGIBLE]".
If the field is blank, value should be null and filled should be false.
'''
print('Form field extraction prompt defined.')
print('Handles: printed forms, questionnaires, applications.')Document Classification Before Extraction
Chain a classification step before extraction to apply the correct extraction schema for each document type:
import json
DOC_SCHEMAS = {
'receipt': receipt_prompt,
'form': form_prompt,
'table': table_json_prompt,
'letter': 'Extract all text preserving paragraph structure. Identify: sender, recipient, date, subject, body.',
'label': 'Extract all text from this label. Include: product name, ingredients/contents, weight, expiry date, barcode numbers.'
}
def classify_and_extract(image_path):
# Step 1: Classify document type
classify_prompt = 'What type of document is this? Return JSON: {"type": "receipt|form|table|letter|label|other", "confidence": "high|medium|low"}'
classification_text = extract_text(image_path, classify_prompt)
doc_type = json.loads(classification_text)['type']
# Step 2: Apply correct schema
schema = DOC_SCHEMAS.get(doc_type, 'Extract all visible text from this document.')
extracted = extract_text(image_path, schema)
return {'type': doc_type, 'data': extracted}
print('Document classify-then-extract pipeline defined.')Low-Quality Image Handling
Not all document images are clear. Prompts should handle degraded images gracefully:
low_quality_prompt = '''
Extract text from this document image. The image may be low quality, blurry, or poorly lit.
Extraction guidelines:
- Extract all text you can read with reasonable confidence
- For unclear sections, use [UNCLEAR] as a placeholder
- For completely unreadable sections, use [UNREADABLE: approximately N words]
- Do not guess or hallucinate words you cannot see clearly
- Note image quality issues at the end: "Image quality: [good/fair/poor]. Issues: [description]"
Be conservative — it is better to mark something as unclear than to guess incorrectly.
'''
print(low_quality_prompt)
print('\nConservative approach: unclear beats hallucinated.')Multi-Page Document Summary
For multi-page documents sent as multiple images, combine page-by-page extraction with a synthesis step:
def extract_multi_page_document(image_paths):
# Step 1: Extract text from each page
page_texts = []
for i, path in enumerate(image_paths):
page_text = extract_text(path, f'Extract all text from page {i+1} of this document. Preserve structure.')
page_texts.append(f'=== PAGE {i+1} ===\n{page_text}')
full_text = '\n\n'.join(page_texts)
# Step 2: Synthesize summary and key information
r = client.messages.create(
model='claude-opus-4-5', max_tokens=500,
messages=[{'role': 'user', 'content': f'''
Here is the extracted text from a {len(image_paths)}-page document:\n\n{full_text}\n\n
Provide:
1. Document type and title
2. 3-sentence summary
3. Key data points extracted
Return JSON: {{"type": str, "title": str, "summary": str, "key_data": [str]}}
'''}]
)
return json.loads(r.content[0].text)
print('Multi-page document pipeline defined.')Validation After OCR Extraction
OCR outputs must be validated before use in downstream systems. Common validation checks:
import re
from datetime import datetime
def validate_receipt_extraction(data):
errors = []
# Validate total is present and numeric
if data.get('total') is None:
errors.append('total is missing')
elif not isinstance(data['total'], (int, float)):
errors.append(f'total is not numeric: {data["total"]}')
# Validate date format
if data.get('transaction', {}).get('date'):
date_str = data['transaction']['date']
try:
datetime.strptime(date_str, '%Y-%m-%d')
except ValueError:
errors.append(f'date format invalid: {date_str}')
# Validate line items total approximately equals subtotal
if data.get('items') and data.get('subtotal'):
items_total = sum(item.get('total', 0) for item in data['items'] if item.get('total'))
if abs(items_total - data['subtotal']) > 0.05:
errors.append(f'Items total {items_total} does not match subtotal {data["subtotal"]}')
return errors
print('Receipt validation function defined.')Extracting Structured Data from Charts and Graphs
Charts and graphs in document images contain data that is invisible to traditional OCR but readable by vision LLMs. A chart extraction prompt asks the model to read the underlying data values:
chart_prompt = '''
Extract the data from this chart or graph image.
Identify:
1. Chart type (bar, line, pie, scatter, table)
2. Title and axis labels
3. All data series names
4. All data points with their labels/values
5. Any notable trend or pattern
Return JSON:
{
"chart_type": str,
"title": str or null,
"x_axis_label": str or null,
"y_axis_label": str or null,
"data_series": [
{"name": str, "values": [{"label": str, "value": number}]}
],
"key_insight": str
}
If exact values are not readable, provide best estimates with a note.
'''
print(chart_prompt)Quick Check
When transcribing handwritten content from an image, what is the recommended approach for illegible words?
OCR and Document Analysis — Key Takeaways
Vision LLMs provide flexible document analysis that goes beyond character recognition:
- Basic extraction: preserve line breaks and paragraph structure; specify this explicitly
- Tables: use markdown table format or JSON rows/headers schema to preserve structure
- Receipts: use a dedicated schema with merchant, items, and totals fields
- Handwriting: instruct [ILLEGIBLE] for unreadable, [PARTIAL] for partially readable — never guess
- Forms: map label-to-value pairs; include filled/not-filled status for each field
- Classify document type first, then apply the appropriate extraction schema
- Validate extracted data programmatically: required fields, numeric types, date formats, math checks
- Low-quality images: conservative extraction beats confident hallucination
Frequently asked questions
Is the “OCR and Document Analysis Prompts” lesson free?
Yes — the full text of “OCR and Document Analysis Prompts” is free to read here on the web, and the AI Prompt Engineering course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the AI Prompt Engineering course, upgrade to CoddyKit PRO.
What will I learn in “OCR and Document Analysis Prompts”?
Extracting text, tables, and structure from document images. You practise AI Prompt Engineering with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start AI Prompt Engineering?
No prior experience is required. AI Prompt Engineering on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “OCR and Document Analysis Prompts” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this AI Prompt Engineering lesson?
Yes. Every AI Prompt Engineering lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Image Description and Captioning Prompts
- Visual Question Answering
- Multi-Image Comparison Prompts
- OCR and Document Analysis Prompts