Why Does Chrome Full-Page Capture Repeat Parts of a Webpage?
Repeated content in a Chrome full-page screenshot can point to a tall-image capture issue or a page that changes while it is captured. Here’s how to identify the cause.
If Chrome’s full-page screenshot repeats part of a webpage, first identify the capture method and where the repetition begins. One Chromium bug report describes corrupted output from the DevTools Protocol Page.captureScreenshot for images taller than 8192 pixels, with content beyond that point repeating the top-left corner. That report is a useful diagnostic clue, especially when duplication starts at a consistent height; it does not establish that the same bug affects your current Chrome version or built-in full-size capture.
Another possibility is that the page changes while it is being captured. Layout shifts and repaints can make parts of a screenshot inconsistent. Sticky elements, infinite scrolling, and other scroll-triggered behavior are also worth investigating, but the available evidence does not establish any one of them as the cause in a particular case.
1. Identify the capture method
Chrome DevTools offers a “Capture a full size screenshot” command for capturing content beyond the visible viewport. A browser extension or an automation client may use a different workflow. The DevTools Protocol also documents Page.captureScreenshot, but its existence does not prove that a particular menu command or extension uses it.
Record how the image was made before changing anything:
- Was it Chrome DevTools’ built-in full-size screenshot, an extension, or a script?
- What Chrome version and operating system were in use?
- What are the screenshot’s pixel dimensions?
- Does the page load content as you scroll or contain independently scrolling areas?
2. Check whether repetition starts at a consistent height
Measure the image height and locate the first duplicated row or section. If the corruption starts near 8192 pixels, compare it with the historical Chromium report. The report specifically describes output beyond 8192 pixels repeating the top-left corner when using Page.captureScreenshot. Treat the match as a lead, not a diagnosis: the report does not tell us whether the issue is fixed or whether it applies to Chrome’s current built-in full-size screenshot path.
If the screenshot is shorter, or the duplicated parts do not start at a stable boundary, investigate page changes and the capture workflow as well.
3. Look for layout shifts and repaints
Chrome DevTools’ Rendering panel includes Layout Shift Regions and Paint flashing diagnostics. Use them to see whether elements move or repaint while you inspect the page.
- Open the page in Chrome DevTools.
- Open the Rendering panel.
- Enable Layout Shift Regions and Paint flashing.
- Observe the page while scrolling or while the page finishes loading.
- Repeat the screenshot after the page appears settled and note whether the repeated area changes.
This is a diagnostic experiment, not a guaranteed fix. If the page is still changing, record what moves and when. Lazy-loaded content, animations, and scroll-triggered updates can make a full-page capture harder to interpret, but their presence alone does not prove they caused the repetition.
4. Compare the built-in command with the original workflow
When the original image came from an extension or automation script, take a separate full-size screenshot using Chrome DevTools. Compare the outputs and note whether the same region repeats at the same height.
- Only the extension or script repeats content: report the exact tool, version, and capture settings to its maintainer. The discrepancy narrows the investigation to differences in capture workflow, but does not reveal the implementation by itself.
- Both outputs repeat content: capture the page URL, Chrome version, operating system, image dimensions, and steps needed to reproduce the result.
- Only one website shows the problem: check whether it changes during scrolling or contains a separately scrolling region. These are hypotheses to test, not established causes.
5. Troubleshooting common symptoms
| Symptom | What to check | Next step |
|---|---|---|
| Everything below a consistent height repeats | Image dimensions and whether the boundary is near 8192 pixels | Include the height and capture method in a bug report; the historical Chromium report is relevant context, not proof of a current bug. |
| Sections are duplicated at irregular positions | Layout changes or repaints using the Rendering panel | Observe the page as it loads and scrolls, then compare a capture after it settles. |
| A sticky header appears in multiple places | Whether the capture was assembled through scrolling and whether the page changes as it scrolls | Compare with DevTools’ built-in full-size command. A repeated header alone does not establish the cause. |
| Only an extension or script produces the bad image | Its version, configuration, and exact capture steps | Reproduce with DevTools and provide both results to the extension or script maintainer. |
| A long page is cut off or has missing lower content | Whether content appears only after scrolling or loading finishes | Check the page’s behavior while scrolling and record when content becomes available. |
| The issue cannot be reproduced consistently | Chrome version, page state, timing, image dimensions, and capture workflow | Keep a record for each attempt; changing several variables at once makes comparison harder. |
6. Make a useful bug report
Include enough detail for someone else to distinguish an image-height problem from a changing-page or workflow problem:
- Chrome version and operating system
- Page URL, if it can be shared
- Screenshot dimensions and the approximate height where repetition begins
- Exact capture command, extension, or automation client
- Whether the page changes during scrolling or loads more content dynamically
- A screenshot and short reproduction steps
Do not assume that updating Chrome will resolve the issue: the available bug report does not establish the current status or applicability.
7. Automate a repeatable capture with Chrome DevTools Protocol
If your goal is to reproduce the protocol-based capture path, the following Node.js example connects to an already-running Chrome instance through the Chrome DevTools Protocol. It captures the page’s current visual viewport; it is not a substitute for Chrome’s built-in full-size screenshot command and does not automatically stitch a tall page.
import { createConnection } from 'node:net';
const host = '127.0.0.1';
const port = 9222;
const pageUrl = 'https://example.com';
const response = await fetch(`http://${host}:${port}/json/new?${encodeURIComponent(pageUrl)}`, {
method: 'PUT'
});
if (!response.ok) throw new Error(`Could not open tab: ${response.status}`);
const tab = await response.json();
const wsUrl = new URL(tab.webSocketDebuggerUrl);
const socket = createConnection({ host: wsUrl.hostname, port: Number(wsUrl.port) });
await new Promise((resolve, reject) => {
socket.once('connect', resolve);
socket.once('error', reject);
});
let buffer = Buffer.alloc(0);
let nextId = 1;
const pending = new Map();
function sendFrame(payload) {
const body = Buffer.from(JSON.stringify(payload));
const mask = Buffer.from([0x13, 0x37, 0x42, 0x99]);
let header;
if (body.length < 126) {
header = Buffer.from([0x81, 0x80 | body.length]);
} else if (body.length < 65536) {
header = Buffer.alloc(4);
header[0] = 0x81;
header[1] = 0x80 | 126;
header.writeUInt16BE(body.length, 2);
} else {
header = Buffer.alloc(10);
header[0] = 0x81;
header[1] = 0x80 | 127;
header.writeBigUInt64BE(BigInt(body.length), 2);
}
const masked = Buffer.from(body);
for (let i = 0; i < masked.length; i++) masked[i] ^= mask[i % 4];
socket.write(Buffer.concat([header, mask, masked]));
}
function call(method, params = {}) {
const id = nextId++;
sendFrame({ id, method, params });
return new Promise((resolve, reject) => pending.set(id, { resolve, reject }));
}
socket.on('data', chunk => {
buffer = Buffer.concat([buffer, chunk]);
while (buffer.length >= 2) {
const opcode = buffer[0] & 0x0f;
const masked = (buffer[1] & 0x80) !== 0;
let length = buffer[1] & 0x7f;
let offset = 2;
if (length === 126) {
if (buffer.length < 4) return;
length = buffer.readUInt16BE(2);
offset = 4;
} else if (length === 127) {
if (buffer.length < 10) return;
length = Number(buffer.readBigUInt64BE(2));
offset = 10;
}
const maskOffset = offset;
if (masked) offset += 4;
if (buffer.length < offset + length) return;
let payload = Buffer.from(buffer.subarray(offset, offset + length));
if (masked) {
const key = buffer.subarray(maskOffset, maskOffset + 4);
for (let i = 0; i < payload.length; i++) payload[i] ^= key[i % 4];
}
buffer = buffer.subarray(offset + length);
if (opcode !== 1) continue;
const message = JSON.parse(payload.toString());
if (message.id && pending.has(message.id)) {
const { resolve, reject } = pending.get(message.id);
pending.delete(message.id);
message.error ? reject(new Error(message.error.message)) : resolve(message.result);
}
}
});
socket.write(`GET ${wsUrl.pathname}${wsUrl.search} HTTP/1.1\r\nHost: ${wsUrl.host}\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n`);
await new Promise(resolve => setTimeout(resolve, 250));
await call('Page.enable');
const result = await call('Page.captureScreenshot', { format: 'png', fromSurface: true });
await import('node:fs/promises').then(fs => fs.writeFile('viewport.png', Buffer.from(result.data, 'base64')));
socket.end();
console.log('Saved viewport.png');
For investigation, keep the tested page and capture path consistent, save the output dimensions, and compare it with a separate full-size DevTools capture. A protocol screenshot of the viewport does not reproduce every full-page capture workflow.
8. Performance, reliability, and cost
Very tall screenshots create large image outputs and are more sensitive to the exact capture path. Pages that continue loading, moving, or repainting also make repeated captures harder to compare. For reliable diagnosis, change one variable at a time and record the browser version, dimensions, and page state.
The cited material provides no frequency estimate for this problem and no benchmark for capture time or memory use. It also does not establish that a browser update fixes the reported 8192-pixel issue. For a one-off local capture, Chrome DevTools is a direct way to inspect the symptom. If you capture pages as part of a service, consider the time spent maintaining browser setup and handling inconsistent page behavior when estimating operational cost.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Its one-call API returns a screenshot or PDF, with PNG, JPEG, and WebP formats. Use the ScreenshotNeo API documentation for parameters and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
FAQ
Does the 8192-pixel report prove Chrome has a current bug?
No. It documents a reported failure in a particular protocol capture context. The available information does not establish its current status or whether it affects Chrome’s built-in full-size command.
Are sticky headers definitely the cause when a header repeats?
No. A repeated header can be a clue to investigate page behavior and capture workflow, but the cited documentation does not establish that cause for an individual screenshot.
Should I update Chrome first?
Record your current version and reproduce the issue with the built-in full-size command first. The research does not establish that an update resolves this symptom.
What details matter most when asking for help?
The capture method, Chrome version, operating system, screenshot dimensions, and the height where repetition begins are the most useful starting details.


