Guides
OCR Integration Guide
A practical guide to integrating OCR into your application — handling multi-page PDFs, choosing the right mode, and optimizing for accuracy.
Overview
This guide walks through common OCR integration patterns. For the complete endpoint reference, see the OCR API Reference.
Choosing the Right Mode
| Use Case | Recommended Mode | Why |
|---|---|---|
| Search indexing | simple | Plain text is easier to index; lower cost |
| Content republishing | formatted | Preserves tables, headings, and structure |
| Data extraction | formatted | Structured output is easier to parse |
| Quick copy-paste | simple | Fastest and cheapest option |
Handling Multi-Page PDFs
Each page is returned as a separate object in the pages array. Use the page-level markdown for per-page processing:
for page in data["data"]["pages"]:
print(f"Page {page['pageNumber']}:")
print(page["markdown"])
print("---")To get the full document as one Markdown string, use the top-level data.markdown field.
Error Handling
Always check success before accessing data. Handle retryable errors with exponential backoff:
import time
def ocr_with_retry(client, payload, max_retries=3):
for attempt in range(max_retries):
response = client.post("/api/v1/ocr", json=payload)
data = response.json()
if data["success"]:
return data
error = data["error"]
if not error["retryable"]:
raise Exception(f"Non-retryable error: {error['code']}")
wait = 2 ** attempt # 1s, 2s, 4s
print(f"Retrying in {wait}s... ({error['code']})")
time.sleep(wait)
raise Exception("Max retries exceeded")Using Idempotency Keys
For production workloads, always use idempotency keys to prevent duplicate charges:
import uuid
payload = {
"image_url": "https://example.com/invoice.pdf",
"mode": "formatted",
}
response = requests.post(
"https://image-to-text.org/api/v1/ocr",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": f"ocr-{uuid.uuid4()}",
},
json=payload,
)
if response.status_code == 409:
# Idempotency conflict — the key was reused with different input
print("Idempotency key conflict — generate a new key and retry")Processing Large Batches
When processing many files, respect rate limits:
- Space requests at least 5 seconds apart
- Track daily usage against your plan's limit
- Monitor credit balance — check remaining credits before submitting large batches
- Use idempotency — protect against accidental double-processing
import time
files = ["doc1.pdf", "doc2.pdf", "doc3.pdf"]
for file_path in files:
response = requests.post(
"https://image-to-text.org/api/v1/ocr",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": f"batch-{file_path}-{int(time.time())}",
},
files={"file": open(file_path, "rb")},
data={"mode": "formatted"},
)
data = response.json()
if data["success"]:
print(f"{file_path}: {data['data']['usage']['credits']} credits")
else:
print(f"{file_path}: Error {data['error']['code']}")
time.sleep(5) # Respect rate limitsBase64 vs File Upload vs URL
| Method | Best For | Considerations |
|---|---|---|
| File upload | Local files, direct access | Simplest for server-side code |
| URL | Files already in cloud storage | Must be publicly accessible |
| Base64 | Generated content, in-memory data | Memory overhead; encode the raw bytes, not a data URI |
Accuracy Tips
- Resolution matters — images below 150 DPI may reduce accuracy
- Good lighting — well-lit, high-contrast documents work best
- Straight alignment — rotated text may be harder to detect
- Clean backgrounds — avoid complex backgrounds behind text
- Standard fonts — handwritten text has lower accuracy than printed text