How to Export a Long Web Page as Tiled Screenshots for a Report
Capture long pages as readable, ordered screenshot tiles, or choose a full-page image or PDF when those formats fit your report better.
To export a long web page as tiled screenshots, capture a series of viewport-sized images from top to bottom at a consistent browser width and zoom. Scroll slightly less than one viewport height between captures so neighboring tiles overlap, then save them in numbered order. Review the tiles for gaps, duplicated content, sticky headers, and text that is too small to read.
Choose the output before you capture: use tiles for manageable report panels, one full-page image for continuous visual context, or a PDF when pagination and printing matter. These methods do not guarantee correct rendering of every dynamic page; inspect the result before sharing it.
1. Choose the right output for your report
| Output | Use it when | Trade-off |
|---|---|---|
| Tiled screenshots | The report needs readable, manageable image panels. | You must preserve order and check for gaps or repeated elements at tile boundaries. |
| One full-page image | You want the page’s visual flow in a single image. | An exceptionally tall image can be awkward to place or read in a paginated report. |
| Pagination, printing, or document delivery matters. | Print styling and page breaks can differ from the live page; review the PDF. |
For a full-page image, Firefox includes a screenshot workflow that can save the full page as an image. For a PDF from Chrome Headless, use --print-to-pdf. For separate panels, repeated viewport captures give you control over tile size and overlap.
2. Prepare the page and capture plan
- Open the page at the width and zoom you want in the report. Keep both fixed for every tile.
- Wait for the page to load. If it uses lazy loading, scroll through the page once to expose below-the-fold content before capturing. This is a practical precaution; browser documentation does not guarantee how every dynamic page behaves.
- Choose a viewport height that leaves enough room for readable content while keeping each image easy to place in the report.
- Plan a small overlap between adjacent images. There is no standard overlap amount; enough repeated content to identify the transition is useful.
- Capture top to bottom and name files in reading order, such as
page-001.png,page-002.png.
Avoid changing browser zoom, viewport width, or page state midway through the sequence. If a tile boundary cuts through a heading, table row, or paragraph, adjust the next scroll position or recapture the affected area.
3. Capture tiles with Chrome Headless
Chrome Headless supports viewport screenshots with --screenshot and --window-size=WIDTH,HEIGHT. Run one capture per tile, changing the scroll position between captures. This shell example uses Chrome’s remote debugging interface from a local shell to scroll and save each viewport. Start a dedicated Chrome process with remote debugging enabled, then run the script in a second terminal.
# Terminal 1: start Chrome with a dedicated profile and remote debugging.
# Replace the executable path if Chrome is installed elsewhere.
chrome --headless --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-tile-profile about:blank
# Terminal 2: set the target and capture settings.
URL='https://example.com/long-page'
WIDTH=1280
HEIGHT=900
OVERLAP=120
OUT='tiles'
mkdir -p "$OUT"
# Open the target in the debugging browser and get its tab WebSocket URL.
TAB=$(curl -s 'http://localhost:9222/json/new?'"$URL" -X PUT)
WS=$(python3 -c 'import json,sys; print(json.load(sys.stdin)["webSocketDebuggerUrl"])' <<< "$TAB")
# Use a small Python WebSocket client to scroll, capture, and save numbered PNGs.
python3 - "$WS" "$WIDTH" "$HEIGHT" "$OVERLAP" "$OUT" <<'PY'
import base64, json, sys, time, urllib.request
from websocket import create_connection
ws_url, width, height, overlap, out = sys.argv[1], *map(int, sys.argv[2:5]), sys.argv[5]
ws = create_connection(ws_url)
next_id = 0
def command(method, params=None):
global next_id
next_id += 1
ws.send(json.dumps({"id": next_id, "method": method, "params": params or {}}))
while True:
message = json.loads(ws.recv())
if message.get("id") == next_id:
if "error" in message:
raise RuntimeError(message["error"])
return message.get("result", {})
command("Page.enable")
command("Runtime.enable")
command("Emulation.setDeviceMetricsOverride", {"width": width, "height": height, "deviceScaleFactor": 1, "mobile": False})
command("Page.navigate", {"url": sys.argv[1] if False else "about:blank"})
# Navigate through the target tab URL supplied as an environment-independent argument.
# Set TARGET_URL below to the page you intend to capture.
target = "https://example.com/long-page"
command("Page.navigate", {"url": target})
time.sleep(3) # Increase this if the page needs more time to render.
scroll = 0
index = 1
while True:
command("Runtime.evaluate", {"expression": f"window.scrollTo(0, {scroll})"})
time.sleep(0.5)
shot = command("Page.captureScreenshot", {"format": "png", "captureBeyondViewport": False})
with open(f"{out}/page-{index:03d}.png", "wb") as f:
f.write(base64.b64decode(shot["data"]))
metrics = command("Runtime.evaluate", {"expression": "({height: document.documentElement.scrollHeight, viewport: window.innerHeight, y: window.scrollY})", "returnByValue": True})["result"]["value"]
if scroll + metrics["viewport"] >= metrics["height"]:
break
scroll += max(1, metrics["viewport"] - overlap)
index += 1
ws.close()
PY
In this example, set target in the Python script to the same page URL as URL. The script requires the Python package websocket-client (python3 -m pip install websocket-client) and a Chrome binary with remote debugging support. The short fixed waits are starting points, not guarantees: pages with delayed content may need more time or an explicit readiness check. Avoid capturing sensitive pages through a debugging browser exposed beyond your own machine.
If you do not need automation, the Firefox screenshot UI is a simpler full-page route: right-click an empty area, choose Take Screenshot, then choose Save full page. Mozilla documents saving either the visible portion or the full page as an image. On Windows or Linux, the shortcut is Ctrl+Shift+S; on macOS, Command+Shift+S. See Mozilla’s Firefox screenshot instructions.
4. Use Firefox DevTools for full-page capture
Firefox DevTools can enable a toolbox screenshot button for full-page capture. Its Web Console also provides the :screenshot helper, including options for full-page capture, delay, device pixel ratio, and filename. For example, after opening the target page in Firefox, use:
:screenshot --fullpage --filename page-full.png
To allow delayed content more time or set the output pixel ratio, use the corresponding :screenshot options documented by Mozilla. Check the saved image at its actual report size; a full-page image may need to be split into tiles for legibility. See Firefox Developer Tools screenshot documentation.
5. Export a PDF with Chrome Headless
If the report needs pagination, use Chrome Headless PDF output rather than stitching images. The following command writes the PDF to the current directory and removes the default date/time and URL/page-number header and footer:
chrome --headless --no-pdf-header-footer --print-to-pdf=report.pdf 'https://example.com/long-page'
Chrome also documents --timeout to limit how long capture waits while page content is loading. For example:
chrome --headless --timeout=10000 --no-pdf-header-footer --print-to-pdf=report.pdf 'https://example.com/long-page'
A timeout limits waiting; it does not prove that all content has loaded. Review page breaks, print styles, and any content that appears only during scrolling. See Google’s Chrome Headless command-line reference.
6. Review and assemble the tiles
- Open the numbered images in order and confirm the first tile starts at the page top and the last includes the page end.
- Use the overlap to verify that no content is missing between panels. Remove the duplicated overlap only if your report layout requires non-overlapping panels.
- Check for repeated sticky headers, cookie banners, chat widgets, blank areas, or content that loaded late. Recapture affected sections if needed.
- Check small text at the size readers will see it in the report, not only when zoomed in on the image file.
- Record the page title, source URL, and capture date/time in a caption or report notes so the screenshots have useful provenance.
- Before sharing, check the report destination’s image dimensions and privacy requirements. A screenshot can include information visible only to the logged-in session.
For an extension workflow, the GoFullPage Chrome Web Store listing describes full-page capture and a feature history that includes PDF export and splitting long captures. Extension features can change, so check the current listing, permissions, and export behavior before use. The listing alone does not establish privacy suitability or current commercial terms.
7. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request can return a PNG, JPEG, WebP, or PDF; the API supports full-page capture and lets you choose other capture settings such as viewport, device preset, wait condition, and output format. See the ScreenshotNeo API documentation for the available options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Cookie and consent banners are accepted before capture, and 60+ known consent platforms, newsletter popups, and chat widgets are removed. Each step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. The response identifies the page verdict and billing status in headers.
- An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
- The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month, with no card required.
8. Troubleshooting
| Problem | Likely cause | What to do |
|---|---|---|
| A tile is blank or shows a loading state | The page had not finished rendering, a request failed, or content appears only after interaction or scrolling. | Wait longer, scroll through once to trigger lazy content, and recapture. For automated captures, use a condition tied to the page’s readiness when possible. |
| Content is missing between tiles | The scroll step was larger than the viewport, or the page height changed as content loaded. | Reduce the step to leave overlap, recalculate page height after loading, and compare neighboring tiles. |
| Tiles repeat too much content | The overlap is large relative to the viewport or the page contains sticky elements. | Reduce overlap if transitions remain clear; account for fixed headers and inspect the report-sized panels. |
| Text is too small in the report | The browser width or zoom produced more content per tile than the report can display legibly. | Use a narrower viewport, fewer columns in the report, or more tiles. Keep width and zoom consistent throughout. |
| Chrome command is not found | The Chrome executable is not on the shell’s PATH or has another installed name. | Use the full path to the Chrome binary for your operating system. |
| PDF has unexpected page breaks or missing background styling | The page’s print CSS differs from screen CSS, or print settings affect backgrounds. | Inspect the PDF and adjust the page’s print stylesheet or capture approach. Do not assume the print layout matches the live page. |
| Firefox screenshot command or button is unavailable | The command is being run outside the Web Console, or the toolbox button has not been enabled. | Use the Firefox screenshot UI or enable the screenshot control in DevTools, following Mozilla’s current instructions. |
9. Performance, reliability, and cost
Tile count grows with page height and the distance advanced per capture. Smaller scroll steps create more overlap and more image files; larger steps reduce the count but make missed content harder to spot. Choose dimensions that remain legible in the destination report and keep a consistent capture setup.
Dynamic pages make capture timing the main reliability concern. Lazy images, delayed scripts, consent dialogs, and content that appears after scrolling may not be present in an early screenshot. Pre-scroll where appropriate, wait for visible readiness, and review every output. Browser documentation describes the capture controls, but does not guarantee correct behavior for every site.
Browser-based captures have no per-image API charge, though they use local compute and manual review time. A screenshot API can reduce browser setup for repeatable or bulk work, but compare its billing rules and options to the report requirements. ScreenshotNeo lists a free allowance of 1,000 shots per month and paid plans from $5 for 3,000; only clean shots are billed, according to the product details above. See the product’s home page and documentation for its API options.
10. Frequently asked questions
Should I stitch the tiles into one image?
Only if the report needs one continuous image. Keep separate panels when readers need to zoom or when a tall image would be hard to place.
How much should adjacent tiles overlap?
There is no documented standard amount. Use a small enough overlap to show where content continues, then verify transitions while reviewing the sequence.
Can I capture a page that requires a login?
A browser can capture what is visible in its authenticated session, but take care not to expose private account information in a report. Keep credentials and debugging access local.
Does a full-page screenshot include everything loaded by scripts?
Not necessarily. Page behavior varies. Scroll through lazy content, allow dynamic sections to render, and inspect the saved output.


