Free tools Windows power users keep installed
One-click scans. No signup required.
If a table-of-contents link works in your Next.js preview but jumps to the wrong place in the exported PDF, check two separate things: whether Paged.js can resolve the link’s fragment to a unique in-document ID, and whether Puppeteer’s Chromium build places the PDF destination correctly. First confirm the link and target are valid, then wait for pagination and layout-affecting assets to finish before calling page.pdf(). If those checks pass, compare the exact Puppeteer and Chromium versions: this symptom has been attributed to a Chromium issue in a report using this stack, but there is no established universal version fix.
First, separate the printed page reference from the clickable PDF link
A cross-reference can appear wrong in two different ways. The page number printed beside a table-of-contents entry may be wrong, or the entry may display the expected number but its clickable destination may land elsewhere. They are related symptoms, but they are not the same part of the output.
- Printed number: Paged.js generates a page reference during pagination. Its
target-counter()function looks up the page containing the element identified by the fragment in the link. - Clickable destination: The exported PDF contains a link destination whose coordinates are produced during the browser’s print operation. Puppeteer’s
Page.pdf()generates the PDF using print CSS, so the Chromium binary is part of this stage.
That distinction matters: if the visible page number is already zero or incorrect in the Paged.js-rendered document, start with fragment matching and pagination readiness. If the HTML preview looks right but clicking the exported PDF link lands ahead or behind, inspect the PDF destination and the exact browser build as well. Paged.js describes the page reference as the page where the element with the matching unique identifier appears (Paged.js Cross References); Puppeteer documents Page.pdf() as its PDF-printing method (PDF generation guide, Page.pdf API).
How Paged.js cross-reference page numbers resolve
A Paged.js cross-reference needs a fragment link that points to an element in the same document. Give the destination a unique id, point the link’s href at that ID, and use a generated-content rule to insert the page counter. For example:
#1 Best Overall
- Create a mix using audio, music and voice tracks and recordings.
- Customize your tracks with amazing effects and helpful editing tools.
- Use tools like the Beat Maker and Midi Creator.
- Work efficiently by using Bookmarks and tools like Effect Chain, which allow you to apply multiple effects at a time
- Use one of the many other NCH multimedia applications that are integrated with MixPad.
<nav aria-label="Contents">
<a class="link" href="#deployment">Deployment</a>
</nav>
<h2 id="deployment">Deployment</h2>
.link::after {
content: ", page " target-counter(attr(href url), page);
}
The link’s fragment is #deployment; the destination’s ID is deployment. The target-counter expression reads the link’s href and asks for the page containing the corresponding target. Paged.js also documents target-text() for retrieving target text. A missing fragment, a target outside the current document, or a target that has not loaded when the function is evaluated can result in a page value of 0 or empty target text (Cross References; Generated Content).
Repair the document before changing browser versions
1. Match every fragment to exactly one ID
For each contents link, copy the fragment after the # and find the destination ID it is meant to identify. Compare the strings exactly, including capitalization and punctuation. An href="#Part-2" does not match id="part-2". Remove accidental whitespace and fix URL-encoding discrepancies rather than assuming the browser will normalize them as you expect.
Check uniqueness too. If multiple elements share an ID, the destination is ambiguous, and a link may resolve to a different element than intended. A quick browser-console check for one suspected target is:
Rank #2
const id = "deployment";
const matches = [...document.querySelectorAll("[id]")]
.filter((element) => element.id === id);
console.log(matches.length, matches);
Run a similar check for each contents target, or add a build-time validation that rejects missing and duplicate IDs. A useful invariant is: every internal contents link has one matching target, and each target ID occurs once.
2. Keep the target inside the document being paginated
Paged.js’s target functions resolve fragments in the current document. A link to another URL, a target in a different document, or a fragment that does not exist in the paginated document cannot supply the intended page number. Check that the document Paged.js receives actually contains the destination—not merely that a Next.js route can render it separately.
3. Do not print while pagination or layout is still changing
Calling page.pdf() too early can capture an incomplete state. The application should wait until Paged.js has finished fragmenting the document and fonts and other layout-affecting assets have loaded. A target that is not loaded when Paged.js processes the cross-reference can yield a zero or empty result. A fixed delay can help diagnose a race, but it is not a durable readiness test: asset and pagination time can vary between runs.
Rank #3
- Save money by using PDF Fusion to view over 100 file formats without having to purchase additional software
- Merge incompatible files quickly and easily by dragging and dropping in PDF Fusion to create a new PDF documents
- Save time with PDF Fusion's editing tools to reuse the content from existing documents without starting from scratch
Use an explicit readiness contract instead. Have the code that owns your Paged.js integration set an application-controlled marker only after pagination is complete; then make Puppeteer wait for that marker before printing. The following pattern is runnable once your page sets window.__PAGED_READY__ = true at the genuine completion point:
const page = await browser.newPage();
await page.goto("http://localhost:3000/report", {
waitUntil: "networkidle0",
});
await page.waitForFunction(() => window.__PAGED_READY__ === true);
const pdf = await page.pdf();
networkidle0 alone is not proof that Paged.js has finished paginating; the app-owned marker is the meaningful gate. If your integration does not expose a completion signal, add one at the point where it knows pagination is done rather than guessing with an arbitrary sleep. Also ensure any web fonts or images that affect wrapping have loaded before setting the marker.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →When HTML looks correct but the PDF destination is offset
Once fragment integrity and readiness are established, compare the rendering environment. The exact-stack report describes a Next.js, Paged.js, and Puppeteer case where HTML links worked but PDF links jumped ahead; the answer attributed that symptom to Chromium (Stack Overflow report). A separate Puppeteer issue describes internal anchors landing around 1.5 pages after the expected section following upgrades (Puppeteer issue #12869). These are individual reports, not proof that every offset has the same cause or that a particular Chromium version fixes it.
Rank #4
- Transform audio playing via your speakers and headphones
- Improve sound quality by adjusting it with effects
- Take control over the sound playing through audio hardware
- Record the pair you actually ran. Note the Puppeteer package version and the exact Chromium executable used in the failing environment. A Puppeteer upgrade can change which browser is involved, so “same code” is not necessarily the same rendering setup.
- Make a small reproducer. Use a short document with a contents link, a unique target ID, enough content to paginate, and the same Paged.js and print path. Keep the HTML and inputs fixed while comparing runs.
- Compare deployed and known-good pairs. Generate the same fixture with the deployed Puppeteer/Chromium pair and another known-good pair. If the destination is misplaced only with one browser line, pin, upgrade, or roll back that pair while investigating. The reports do not establish a universal fixed version.
- Check both outputs separately. Confirm the generated page number in the rendered document, then open the exported PDF in a viewer and test both its displayed reference and its clickable destination. A correct HTML preview does not prove the PDF’s destination coordinates are correct.
Keep rendering reproducible across development and production
Paged.js warns that output can differ between browsers and operating systems and recommends keeping the browser and OS consistent between design and PDF generation (Paged.js: W3C specifications for printing). For a stable PDF pipeline, keep the environment that creates the preview as close as practical to the one that creates the production file.
- Record the Puppeteer version, Chromium executable or build, operating system, and relevant font setup alongside a failing artifact.
- Use the same browser/OS combination for visual review and generation where possible.
- When changing a browser dependency, regenerate a small cross-reference fixture and check its visible numbers and destinations before shipping.
- Retain a failing PDF and its source input so a version comparison is reproducible rather than based on memory.
Puppeteer’s Page.pdf() uses print CSS media, which is another reason to validate the actual generated PDF rather than infer its behavior from a screen-media preview (Puppeteer Page.pdf API). The rendering path includes Paged.js pagination and Chromium’s print operation; a change in either can affect what you see.
Troubleshooting by symptom
| Symptom | Likely check | Action |
|---|---|---|
Printed reference is 0 or blank |
Fragment target is missing, outside this document, mismatched, or unavailable when Paged.js evaluates it. | Verify one matching in-document ID, correct the fragment, and wait for pagination and relevant assets before export. |
| Reference points to the wrong section | Duplicate IDs, typo, case difference, or an incorrect fragment. | Make target IDs unique and compare each href fragment against the intended destination exactly. |
| HTML navigation works; PDF click lands ahead | Chromium’s generated PDF destination may be wrong even though the browser link resolves. | Test the exported file in a PDF viewer, then compare the exact Puppeteer/Chromium pair using a fixed fixture. |
| Issue appears after dependency or environment upgrade | The browser binary, Puppeteer version, or OS changed. | Record the versions and environment; compare with a known-good pair, then pin, upgrade, or roll back while investigating. |
| Output changes between runs or machines | Pagination may be racing with assets, or browser/OS differences may alter layout. | Add an explicit completion gate for pagination and stabilize browser, OS, and layout-affecting assets. |
Or skip the browser setup
ScreenshotNeo is a website screenshot API, not a Paged.js or PDF cross-reference repair tool. It can be useful for capturing a webpage for visual inspection, but it does not generate a PDF or verify a PDF link’s destination. If you need a screenshot of a page while debugging its HTML appearance, one GET request can return an image. See the ScreenshotNeo website and API documentation.
Recommended Free Tools
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Cookie banners are accepted and removed before capture, along with known consent platforms, newsletter popups, and chat widgets; those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response includes page-verdict and billing headers. ScreenshotNeo also has an MCP server with tools for AI agents, and its Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. These features can simplify webpage screenshot capture, but PDF link correctness still needs to be tested in the actual exported PDF.
Sign up free for 1,000 screenshots a month with no card.
Frequently Asked Questions
Is there a known Chromium version that fixes this offset?
The cited reports do not establish a universal fixed version. Compare the exact Puppeteer/Chromium pair that fails with a known-good pair using the same fixture.
Are the reported page offsets typical for this stack?
No frequency or average offset is established. The reported offsets are individual issue descriptions, not generalizable statistics.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsQuick 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.




