ProductOctober 28, 20262 min read
An OpenRouter for OCR: offering many OCR models in your product
Why platforms that parse documents should let users pick an OCR model, and how to add PaddleOCR-VL, GLM-OCR, Mistral, Azure, Google, and Textract behind one API.
OpenRouter made it normal to call dozens of language models through one API. You keep one key and one bill, and changing models is a string in the request. OpenParser does this for OCR: ten OCR models behind POST /parse, selected per request with ocr_model.
If you are building a product that reads documents, such as AP automation or contract review, we think the OCR model should be a setting your product can change per customer.
One OCR model rarely fits every customer
The models differ in ways your customers notice. A cloud OCR API that returns plain text and line boxes is fine for search indexing and useless for a table-heavy bank statement. Layout models such as PaddleOCR-VL and GLM-OCR return headings, tables, formulas, and figures as typed regions. Some customers are contractually tied to Azure or AWS and will only accept processing there.
Price spreads are large too. On our catalog, the cheapest layout model is $1 per 1,000 pages and the most expensive table extraction is $17.25. A customer parsing two million pages a month will care which one you picked for them.
And the field moves. GLM-OCR from Z.ai appeared in 2026 with strong published results on OmniDocBench. If your stack is wired to one vendor's response format, every new model means a new integration.
What a router changes
With OpenParser, each request names a model:
import { readFile } from 'node:fs/promises';
import { OpenParserClient } from '@openparser/sdk';
const client = new OpenParserClient();
const file = new File([await readFile('statement.pdf')], 'statement.pdf', {
type: 'application/pdf',
});
const parsed = await client.parse.sync(
{ ocr_model: customer.ocrModel ?? 'paddleocr-vl-1.6', output_format: 'openparser@1' },
file
);The response is the same openparser@1 document whichever model ran: pages, typed elements with bounding boxes, and markdown. Your downstream code (extraction, review screens, exports) never branches on the vendor. GET /models/ocr lists the live catalog with prices and capabilities, so your settings page can render the options without hardcoding them.
Patterns that work in a product
Start with a sensible default and hide the choice. Most users never need to see it. We default to an open-weight model because it costs the least and handles general documents well.
Let admins pick per workspace or per document type. Invoices and statements may parse best on one model, scanned handwritten forms on another. Store the choice next to the document type, then pass it through as ocr_model.
Fall back on failure. Vendors have outages. Because every model returns the same format, a fallback is a few lines:
import { OpenParserError } from '@openparser/sdk';
async function parseWithFallback(file: File, models: string[]) {
for (const ocr_model of models) {
try {
return await client.parse.sync({ ocr_model, output_format: 'openparser@1' }, file);
} catch (error) {
if (!(error instanceof OpenParserError) || error.status < 500) throw error;
}
}
throw new Error('All OCR models failed');
}
await parseWithFallback(file, ['glm-ocr', 'paddleocr-vl-1.6', 'mistral-ocr-4-1']);Compare before you switch. Run the same sample through two models and look at the elements as well as the text. We wrote up how to compare OCR models on your own documents.
Open weights next to cloud APIs
OpenRouter routes to models that other companies host. For OCR we do some of the hosting ourselves. PaddleOCR-VL and GLM-OCR run on GPUs that OpenParser operates, which is why they cost $1 per 1,000 pages. Mistral, Azure, Google, and AWS Textract requests go to those vendors. Both kinds sit behind the same request and response, so a customer can move from a cloud API to an open-weight model, or back, without a migration.
If you want the details of how we host an open-weight model, read Hosting GLM-OCR on one L4 GPU. To try the router, create a key in Studio; new accounts get $10 in credits.