The most credible explanation is tagged PDF output. Puppeteer enabled tagged-PDF export by default around version 11, and users subsequently reported much larger files, including a version 12 report containing a /StructRootTree. That makes PDF structure a plausible cause, but it does not establish a universal Puppeteer 12 bug. Reproduce the change with the same browser, headless mode, HTML, assets, and print options, then compare tagged: true with tagged: false if your installed release supports that option.
What changed around Puppeteer 11 and 12?
Puppeteer’s historical behavior changed when Chromium’s tagged-PDF export was enabled by default. Tags add a logical structure tree used for accessibility technology. That metadata can be substantial, especially in long documents, even though the visible pages may look the same.
| Report | Earlier output | Later output | What was observed | How to interpret it |
|---|---|---|---|---|
| Puppeteer issue #8100 (2022) | 1.5 MB for 539 pages before 11.0.0 | 45.7 MB in 11.0.0 | The reporter associated the increase with --export-tagged-pdf being enabled by default and described tags as accessibility support. |
A historical, user-reported example—not a guaranteed multiplier for other documents. |
| Puppeteer issue #9124 (2022) | 3 MB before the upgrade | 16 MB after upgrading to 12.0.0 | The reporter said the larger file contained /StructRootTree. |
The issue was closed as not planned and did not confirm a universal root cause. |
These reports explain why many developers associated the size jump with “version 12,” even though the clearest documented change occurred with tagged export in the 11.0.0 timeframe. A version upgrade can also change the bundled Chromium binary or the headless implementation, so the Puppeteer package number alone is not enough to identify the cause.
Why tagged PDFs can be much larger
A tagged PDF carries structural information such as the relationships between document content, headings, paragraphs, tables, and other elements. Screen readers and other accessibility tools can use that structure. A long report therefore has more than painted page content: it also has a tree describing the document’s organization.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall#1 Best Overall
The current Puppeteer PDF options documentation lists tagged as an experimental option to generate a tagged (accessible) PDF and documents its default as true. Check the documentation that matches the Puppeteer release installed in your project; option availability and defaults are release-specific.
Turning tags off can reduce the output when the structure tree is the dominant contributor, but it removes that accessibility metadata. Treat the smaller file as a trade-off, not as a universally correct fix. If the PDF is intended for users who rely on assistive technology, preserve tags and investigate other contributors instead.
Why this is not proof of a universal v12 bug
The two issue reports are valuable clues, not controlled benchmarks. They concern different documents, page counts, assets, and environments. One report attributes the change to tagged export; the other notes /StructRootTree but does not establish that it is the sole reason for every size increase. No published statistic supports a fixed percentage or multiplier for all PDFs.
A later report also connected larger files with changing the headless setting. A Puppeteer maintainer explained that, in that setup, headless: 'new' follows headful browser behavior while headless: 'shell' selects the old headless mode. That is a separate variable and should not be presented as confirmation of the version 12 report’s cause.
Rank #2
Variables to keep identical during a comparison
Change one thing at a time. Record all of the following for each run:
- Puppeteer package version.
- Chromium or Chrome version, executable path, and launch arguments.
- Headless mode.
- Operating system and installed fonts.
- Exactly the same HTML, images, stylesheets, scripts, and remote responses.
- Print options, including paper format, margins, scale, background printing, page ranges, and display header/footer settings.
- Page count and resulting file size.
- Whether tagged output is enabled.
Puppeteer’s normal installation selects a particular Chrome version, while an explicit executable path can select another one. Record the actual browser version rather than assuming that two Puppeteer releases are using equivalent Chromium builds.
Reproduce the difference with a controlled Node.js test
The following script creates one PDF with a fixed launch configuration and reports the browser version, page count, and file size. Set TARGET_URL to the page you are investigating. Use the same URL and environment for every run.
const puppeteer = require('puppeteer');
const fs = require('fs');
(async () => {
const target = process.env.TARGET_URL || 'https://example.com';
const tagged = process.env.TAGGED !== 'false';
const output = tagged ? 'report-tagged.pdf' : 'report-untagged.pdf';
const browser = await puppeteer.launch({ headless: true });
try {
const browserVersion = await browser.version();
const page = await browser.newPage();
await page.goto(target, { waitUntil: 'networkidle0' });
await page.pdf({
path: output,
format: 'A4',
printBackground: true,
tagged
});
const pages = await page.evaluate(() => Math.ceil(document.documentElement.scrollHeight / window.innerHeight));
const bytes = fs.statSync(output).size;
console.log(JSON.stringify({ output, tagged, browserVersion, pages, bytes }, null, 2));
} finally {
await browser.close();
}
})();
Run the same script twice:
node measure.js
TAGGED=false node measure.js
If your installed release does not recognize tagged, use the release’s matching PDF options documentation before drawing conclusions. Do not silently compare an older release that ignores the option with a newer release that honors it.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Inspect whether a structure tree is present
As a quick diagnostic, search a copy of the generated PDF for the structural-tree name reported in issue #9124:
grep -a '/StructRootTree' report-tagged.pdf
grep -a '/StructRootTree' report-untagged.pdf
This is an indicator, not a complete PDF validator. A match shows that the file contains the named structure object; it does not measure how much of the file it occupies or prove that no other resource caused the growth.
How to decide whether to disable tagging
Keep tagged: true when accessibility matters
Retain tagged output for documents whose accessibility structure is required or expected. Instead of optimizing only for bytes, profile the generated files and look for unusually large images, embedded fonts, or other document-specific resources while keeping the accessibility setting unchanged.
Test tagged: false for non-accessibility workflows
If your use case does not need tagged structure, generate a controlled untagged comparison. Measure the size reduction and verify that downstream consumers still accept the PDF. Make the choice explicit in code and document why accessibility tags are not required.
Rank #4
Do not rely on the old launch-argument workaround by default
Issue #8100 describes a historical workaround using ignoreDefaultArgs: ['--export-tagged-pdf']. That report is evidence of what worked for that environment, not a current guarantee. The supported, release-specific tagged PDF option is the clearer setting when your Puppeteer version provides it.
Headless mode can change the result independently
When a size change appears after changing headless, repeat the test with the same mode on both versions. In the setup discussed by the maintainer, 'new' and 'shell' selected different browser paths. Do not attribute a headless-mode change to tagged output without a run where tagging is the only variable.
Troubleshooting checklist
| Symptom | Likely explanation | Action |
|---|---|---|
| Large increase begins with Puppeteer 11 or later | Tagged export may now be enabled. | Run identical jobs with tagged: true and tagged: false; inspect the structure indicator. |
Changing tagged barely changes size |
Images, fonts, embedded files, or page content may dominate. | Hold content constant and profile resources; do not assume tags are the cause. |
| Results differ after a package-only upgrade | The bundled Chromium version may also have changed. | Log browser.version() and executable path, then compare with a fixed browser binary. |
Results differ after changing headless |
Different headless implementations can produce different output. | Choose one mode and keep it fixed while testing package and tagging changes. |
The older release rejects tagged |
The option is not available or is documented differently in that release. | Use the matching API documentation; do not infer behavior from current documentation. |
| Disabling tags solves size but fails an accessibility requirement | The optimization removed needed structure. | Restore tags and optimize content-specific resources instead. |
Or skip the browser setup
If your goal is a clean capture of a URL rather than maintaining Chromium and Puppeteer yourself, ScreenshotNeo provides a website screenshot API and MCP server. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Only clean shots are billed: bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
For a one-request capture, see the ScreenshotNeo API documentation and use:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
open('shot.webp', 'wb').write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Every plan includes its features. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.
Best Value
- Used Book in Good Condition
Frequently Asked Questions
What does /StructRootTree mean in a PDF?
It is the object name for a PDF structure tree. Its presence supports the observation that structural tagging is involved, but it does not quantify the tree’s size or prove that it caused every byte of an increase.
Why should CI logs include the browser version?
Puppeteer can install one Chrome version by default, while an explicit executable path can select another. Two package versions may therefore produce different PDFs for reasons unrelated to the JavaScript API change.
Are the reported 45.7 MB and 16 MB increases normal?
They are individual 2022 user reports, not representative benchmarks. There is no established universal percentage or multiplier for Puppeteer-generated PDFs.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

