Full-page screenshots that are actually complete: lazy loading, sticky headers, 100vh layouts and emoji
Disclosure: I build and sell one of the three screenshot tools compared below, a hosted screenshot Actor on Apify. This article was written with the help of AI; the numbers come from the public benchmark data linked at the end, and everything here works in a plain Playwright or Puppeteer script. page.screenshot({ fullPage: true }) looks done until you look at the output: blank rectangles where…
The article discusses issues that commonly arise when capturing full-page screenshots using various tools. Three screenshot tools are compared: the author's own hosted screenshot Actor on Apify, apify/screenshot-url, and cheapapi/website-screenshot-api. The author provides insight into the problems encountered and how they were resolved.
1. Lazy-loaded images: Images below the fold load only when they come close to the viewport, causing blank rectangles in the captured screenshots. To fix this, the author scrolls the page in steps, waiting for pending images, and then goes back to the top before capturing. This process is capped at 30,000 pixels to prevent infinite scrolling on infinite feeds. Additionally, the author ensures that broken images do not fail the entire capture process.
2. Sticky and fixed elements: Sticky headers and fixed layers can appear in multiple slices of a stitched screenshot and may be painted in the wrong place. The author resolves this by either forcing the position to relative for sticky headers or switching fixed bars to absolute coordinates, so they appear once at the top. Other fixed layers, such as chat bubbles, back-to-top buttons, and bottom bars, are hidden before capturing.
The author also checks the layout before capturing, as some headers only become fixed after scrolling or after a specific trigger.
3. Capture speed and 100vh layouts: Capturing full-page screenshots can take longer, especially for large layouts with 100vh sections. The author solves this by resizing the viewport to the page height for each slice, but this approach does not work well for layouts built from 100vh sections. Instead, the author falls back to a normal-size viewport and stitches the slices together. Some pages use a scrolling element other than the window body, requiring a different approach to capture correctly.
4. Emoji and CJK fonts in containers: Some slim Docker images have no color-emoji font, causing emojis to appear as tofu boxes. To address this, the author suggests installing Debian packages containing fonts-noto-color-emoji and fonts-noto-cjk, followed by running fc-cache -f to update the font cache.
5. Cookie walls and bot checks: Consent banners, such as cookie walls, can be dismissed by blocking the consent manager's script or clicking the "accept" button before capturing. However, the author cautions against bypassing CAPTCHAs and instead recommends detecting the challenge page and reporting an error instead of an image of it. The author notes that many normal pages may load an invisible reCAPTCHA badge, which should only be treated as a block if visible.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.