Your Generated PDFs Open Slowly in the Browser? They Are Probably Not Linearized
Last month a user emailed me about a report my little side project generates: "The PDF takes forever to show the first page. I thought it was broken."
The file was 4 MB. Not huge. But the in-browser preview sat on a spinner for several seconds before page one appeared, and on hotel Wi-Fi it was worse. The PDF itself was fine — it opened instantly in a desktop reader once fully downloaded. That was the clue: the browser could not render page one until it had downloaded essentially the whole file.
This post is the diagnosis and the fix, because if your app generates PDFs (invoices, reports, statements, tickets), your users are probably hitting the same thing.
The actual problem: byte order, not file size
A regular PDF is laid out for a writer, not a reader. The cross-reference table and page resources can sit anywhere in the file, objects for page one may be scattered from byte 0 to byte 4,000,000, and a viewer that wants to draw the first page has to go hunting — which, over HTTP, means range requests all over the file or just downloading everything.
Linearization (Adobe calls it "Fast Web View") restructures the file specifically for this:
- Page one's objects are moved to the front of the file, in order.
- A hint table up front tells the viewer exactly which byte ranges it needs for each page.
- The viewer can then fetch just the first page's bytes with an HTTP range request and render immediately, pulling later pages on demand as the user scrolls.
Same content, same visual result, completely different first-paint behavior. The spec detail that matters: the file's first line carries a linearization marker in the header comment, and you can check for it:
# quick check: is this PDF linearized?
head -c 1024 report.pdf | grep -a "Linearized"
# or with qpdf, if you have it installed:
qpdf --check report.pdf | grep -i linearized
If those come back empty, your generated PDFs are not linearized — no matter what library produced them. Most generators (including the very common ones) do not linearize by default, because it is a second full pass over the file.
What I measured on my own file
Personal test, one file, throttled connection (Chrome DevTools "Slow 4G" profile), before and after linearizing the exact same generated report:
| Before | After linearization | |
|---|---|---|
| File size | 4.1 MB | 4.2 MB (slightly larger — hint tables cost bytes) |
| Bytes needed to render page 1 | ~4.1 MB (effectively all of it) | ~180 KB |
| Time to first page on screen | ~3.5 s | under 0.5 s |
Two things worth noting from that table. First, the linearized file got marginally bigger, and that is normal — you are trading a few percent of size for page-at-a-time delivery. Second, the win is not "the file loads faster"; it is "the first page renders after ~4% of the bytes." On a fast office connection nobody noticed the problem. On the connections your users actually complain from, it is the whole experience.
Your numbers will differ — this was my file, my hosting, my throttle profile — but the mechanism is deterministic: if page one needs the whole file, slow networks will feel it linearly.
The fix, at three levels
Level 1 — your generator. Some toolchains can emit linearized output directly or via a post-processing flag. If yours can, turn it on in the generation pipeline and be done. The post-processing step in pseudo-code is trivial; the cost is one extra pass per file:
generate report.pdf
linearize report.pdf -> report-web.pdf
serve report-web.pdf (with a server that honors Range requests)
Level 2 — your server. Linearization only pays off if your hosting actually answers HTTP Range requests with 206 Partial Content. Most static hosts and CDNs do. Check yours:
curl -sI -H "Range: bytes=0-1023" https://your-host/report.pdf \
| grep -iE "HTTP/|accept-ranges|content-range"
If you see 200 instead of 206, the browser will fall back to downloading everything and the linearization buys you almost nothing. Fix the serving layer first.
Level 3 — one-off files. For PDFs that already exist (a backlog of generated reports, files clients send you, anything not flowing through your pipeline), you just need a linearizer. I used the one in PDFLean — the dedicated tool page is pdflean.com/tools/pdf-linearize — dropped the original report in, downloaded the processed copy, and verified it with the head/grep check above before swapping it into my test. For a one-off fix or a sanity check before you automate anything, that is the fastest path: process, verify the marker is there, re-measure.
The checklist I now run for generated PDFs
- Generate a sample with production-like data (empty test files hide this — you need real length).
- Check the linearization marker (command above).
- Confirm the host returns
206for a range request. - Throttle the connection and time first-page render, not full download.
- Only then argue about compression — size and structure are separate problems, and structure is the one that blocks first paint.
That user who emailed me never wrote back, which in support terms is the best possible outcome. The report did not get smaller or prettier. It just stopped making people wait for page one.
Top comments (0)