Puppeteer’s page.screenshot({ fullPage: true }) command is a powerful way to capture an entire webpage as a single image or PDF. Yet developers frequently encounter a frustrating issue: fixed-position headers—like navigation bars—either vanish, appear in the wrong place, or render inconsistently across multiple pages. When you inspect the site in a standard browser or even in Puppeteer’s viewport mode, everything looks normal. The problem only emerges during full-page captures.
Why does this inconsistency occur?
The core issue: viewport vs. document rendering
When Puppeteer uses fullPage: true, it leverages Chrome’s DevTools Protocol to render content beyond the visible viewport. However, elements with position: fixed are positioned relative to the viewport, not the document. If your script has scrolled to the bottom of the page before taking the screenshot, the fixed header—logically at the top of the viewport—gets captured at the bottom of the rasterized document. The result? A header in the middle of the image, blank space at the top, or the header only appearing on the first page of a multi-page output.
A second, subtler cause compounds the problem: many modern websites apply scroll-behavior: smooth to the root HTML element. When your script calls window.scrollTo(0, 0), the browser initiates a smooth animation to the top. Puppeteer may capture the page before this animation completes, leaving the header in a transitional state—partially visible, misaligned, or hidden.
A reliable fix: reset, scroll, and wait
To ensure consistent full-page screenshots, three steps must be taken immediately before capturing:
- Disable smooth scrolling so
scrollTo(0, 0)is instantaneous. - Reset any JavaScript-driven transformations that hide or transform headers during scroll events.
- Explicitly scroll to the top and allow the browser time to render the updated state.
Here’s a production-ready function that automates this process:
async function prepareForScreenshot(page) {
await page.evaluate(() => {
// Disable smooth scrolling across the entire document
const style = document.createElement('style');
style.textContent = 'html { scroll-behavior: auto !important; }';
document.head.appendChild(style);
// Reset fixed/sticky headers to their default visible state
const headers = document.querySelectorAll(
'header, .header, [class*="header" i], nav[class*="header" i]'
);
headers.forEach(el => {
const cs = window.getComputedStyle(el);
if (cs.position === 'fixed' || cs.position === 'sticky') {
el.style.setProperty('transform', 'none', 'important');
el.style.setProperty('opacity', '1', 'important');
el.style.setProperty('visibility', 'visible', 'important');
if (cs.display === 'none') {
el.style.setProperty('display', 'flex', 'important');
}
// Remove common classes that hide headers on scroll
['hidden', 'is-hidden', 'scroll-up', 'scroll-down', 'header--hidden']
.forEach(c => el.classList.remove(c));
}
});
// Force immediate scroll to top
window.scrollTo(0, 0);
});
// Allow one render frame for changes to settle
await new Promise(r => setTimeout(r, 300));
}Call this function just before your screenshot command:
await prepareForScreenshot(page);
await page.screenshot({ path: 'out.png', fullPage: true });Handling advanced cases: synthetic events and overlays
For most static or moderately dynamic sites, the fix above resolves the issue entirely. However, some websites use JavaScript scroll event listeners that re-evaluate header visibility after your reset code runs. In such cases, dispatching a synthetic scroll event can prompt the site’s own logic to re-hide the header correctly:
window.scrollTo(0, 0);
window.dispatchEvent(new Event('scroll'));Additionally, sites with transparent fixed headers overlaid on hero sections (a common modern design pattern) typically render correctly once the viewport and document alignment are fixed. The header simply overlays the hero image as intended.
A practical tool built on these fixes
This exact solution powers Site2PDF, a service that converts websites into PDF, PNG, JPG, or ZIP archives. The platform offers a free tier with five archives per month, including advanced options like cookie banner removal, sticky header unfixing, and accordion expansion. The tool is designed to bring browser-like fidelity to automated exports—without the quirks of headless rendering.
As web applications grow more interactive, automated screenshot reliability becomes critical. Whether you're auditing UI consistency, generating documentation, or archiving content, mastering Puppeteer’s fullPage behavior ensures your outputs reflect the true user experience.
AI summary
Stop Puppeteer fullPage screenshots from hiding or misplacing fixed headers. Learn the root cause and apply a proven fix with JavaScript and CSS tweaks for accurate screenshots.
Tags