SnapDOMGitHub★ 8K
How-To Recipe

Capture a full web page

Snapshot the document’s rendered DOM rather than only the visible viewport.

TL;DR

Pass document.documentElement or a dedicated page wrapper to SnapDOM.

Copy-paste example

Install @zumer/snapdom, select the rendered element, and capture it:

const page = document.documentElement
const capture = await snapdom(page, {
  embedFonts: true,
  outerShadows: true,
})
await capture.download({ format: 'png', filename: 'full-page' })

Why this pattern works

Capturing the root includes the document’s layout beyond the current viewport. A dedicated content wrapper is often preferable when fixed navigation or overlays should be excluded.

Capture content beyond a viewport

This scrollable preview is intentionally tall; capture exports the complete selected DOM subtree.

Long-form page
01

Hero section

Content rendered below the initial visible area remains part of this DOM element.

02

Features

Content rendered below the initial visible area remains part of this DOM element.

03

Customer story

Content rendered below the initial visible area remains part of this DOM element.

04

Pricing

Content rendered below the initial visible area remains part of this DOM element.

05

Final call to action

Content rendered below the initial visible area remains part of this DOM element.

The captured result will appear here.

Pages taller than the canvas limit

With the default SVG engine, PNG file exports automatically preserve the requested resolution beyond canvas limits. SnapDOM renders the frozen capture in windows and encodes one PNG file:

const capture = await snapdom(page)
await capture.download({ format: 'png', scale: 2 })
// Or get a file to upload/store:
const blob = await capture.toBlob({ format: 'png', scale: 2, dpr: 1 })

download() always uses DPR 1. This automatic path requires CompressionStream; older browsers keep the existing downscale and warning. Large files still need encoding time and memory, and image viewers have their own limits.

toCanvas(), toPng() and JPEG/WebP exports keep the single-canvas size guards: 16,384px per side in Safari, 32,767px in Chrome/Firefox, plus an area limit. If you need separate canvases, export pieces with crop:

const capture = await snapdom(page)
const { contentX, contentY, w0, h0 } = capture.meta
const pieceHeight = 4000 // CSS px

for (let y = 0; y < h0; y += pieceHeight) {
  const canvas = await capture.toCanvas({
    scale: 2,
    dpr: 1,
    crop: { x: contentX, y: contentY + y, width: w0, height: Math.min(pieceHeight, h0 - y) }
  })
  // save or upload this piece, then move on
}

crop is a rectangle in the coordinates of capture.meta, and each call returns one canvas. The capture runs once; only the rasterization repeats. Keep pieceHeight × scale × dpr under the limit. How tiling works.

Limits and common mistakes

Very large pages create large SVG and bitmap surfaces. For huge or virtualized documents, capture logical sections or render hidden items before capture.

Frequently asked questions

Is this the same as a viewport screenshot?

No. A viewport screenshot captures visible screen pixels; this captures the selected DOM subtree and its layout extent.

Will lazy content be included?

Only content that exists and has resolved. Load or render lazy sections before starting capture.

Capture it in the browser

Install SnapDOM and turn the DOM your users already see into a portable image.

Open the demoInstallation