EngineeringOctober 28, 20262 min read
Hosting GLM-OCR on one L4 GPU: what we measured
How OpenParser serves Z.ai GLM-OCR with vLLM behind the PaddleOCR layout-parsing contract, with throughput, memory, and cost per page on an NVIDIA L4.
Most OpenParser traffic goes to hosted PaddleOCR-VL. Teams want a good open-weight OCR model without running GPUs themselves. We added a second one: Z.ai's GLM-OCR, available today as ocr_model: "glm-ocr" at the same $1 per 1,000 pages.
This post covers how we host it, what one GPU delivers, and what it costs.
Why GLM-OCR
GLM-OCR is a compact document OCR model: a CogViT vision encoder and a GLM-0.5B language decoder, about 0.9B parameters in total. The weights are MIT licensed. Z.ai reports 94.62 on OmniDocBench v1.5 on its model card.
It was easy to add because GLM-OCR's recommended pipeline detects layout with PP-DocLayoutV3, the same layout model PaddleOCR-VL uses. Both models find the same regions (headings, paragraphs, tables, formulas, figures) and only differ in how they read each region.
One contract for both models
Our worker already speaks PaddleOCR's /layout-parsing contract. That client handles the hard parts of OCR at scale: splitting large PDFs into page ranges, bisecting chunks that time out, checkpointing finished chunks, and mapping page coordinates.
We built a small gateway that answers the same contract for GLM-OCR, so the worker reuses that client unchanged:
The gateway runs the official glmocr SDK pipeline, then translates its output. GLM-OCR returns boxes normalized to 0 to 1000; we scale them to page pixels. It writes headings and display math with Markdown markers; we strip those, because the OpenParser renderer adds them back from each element's role. Everything after that (the openparser@1 document graph, markdown, and /extract citations) is shared with PaddleOCR-VL.
The SDK imports PyMuPDF, which is AGPL, so we install the SDK without its dependencies, satisfy the import with a stub, and rasterize PDFs with pypdfium2. The image build downloads both models from fixed Hugging Face commits and checks every file's sha256 before using it.
Documents never leave our GPUs: the gateway refuses to start if the SDK's cloud mode is enabled.
What one L4 delivers
We benchmarked on one g6.xlarge (a single NVIDIA L4, 24 GB) with 32 dense pages of an academic paper: formulas, tables, and figures, about 10 regions per page.
| Requests in flight | Pages per second | Seconds per page | GPU utilization |
|---|---|---|---|
| 1 | 0.54 | 1.84 | 92% |
| 2 | 0.55 | 1.82 | 97% |
One document at a time already saturates the GPU, because the pipeline fans each page's regions out to vLLM in parallel. That works out to roughly 2,000 dense pages per hour per GPU. Business documents with fewer regions per page parse faster.
Peak memory was 19.2 of 23 GB on the GPU. A cold host is ready in about two minutes once images are cached.
What it costs
An on-demand g6.xlarge in us-east-2 costs about $0.80 per hour. At $1 per 1,000 pages, one warm GPU breaks even at about 800 dense pages per hour, or 41% of its capacity. We run one host in production and add a second when the queue grows.
Try it
Set ocr_model to glm-ocr on any /parse request:
curl https://api.openparser.dev/parse \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-F 'request={"ocr_model":"glm-ocr","output_format":"openparser@1"};type=application/json' \
-F "file=@invoice.pdf"Not sure which open-weight model fits your documents? Read GLM-OCR vs PaddleOCR-VL, then run the same PDF through both in the playground. New accounts get $10 in free credits.