<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: OpenCapture</title>
    <description>The latest articles on DEV Community by OpenCapture (@opencapture).</description>
    <link>https://dev.to/opencapture</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4107321%2F4db0a118-996c-49db-a162-a44f03344056.png</url>
      <title>DEV Community: OpenCapture</title>
      <link>https://dev.to/opencapture</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/opencapture"/>
    <language>en</language>
    <item>
      <title>What permissions a screenshot extension asks for, and what they actually let it do</title>
      <dc:creator>OpenCapture</dc:creator>
      <pubDate>Thu, 08 Oct 2026 15:47:01 +0000</pubDate>
      <link>https://dev.to/opencapture/what-permissions-a-screenshot-extension-asks-for-and-what-they-actually-let-it-do-547i</link>
      <guid>https://dev.to/opencapture/what-permissions-a-screenshot-extension-asks-for-and-what-they-actually-let-it-do-547i</guid>
      <description>&lt;p&gt;“Read and change all your data on all websites” is the scariest sentence in the Chrome Web Store, and most screenshot extensions trigger it. It is worth knowing what it means, because it is avoidable — and an extension that avoided it is telling you something.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; A full-page screenshot tool has to run code inside the page in order to scroll it and measure it. There are two ways to get that ability: &lt;strong&gt;&lt;code&gt;activeTab&lt;/code&gt;&lt;/strong&gt;, which grants access to one tab, only when you click the toolbar button, and only until you navigate away; or a broad &lt;strong&gt;host permission&lt;/strong&gt; such as &lt;code&gt;&amp;lt;all_urls&amp;gt;&lt;/code&gt;, which grants standing access to every page you ever visit. Both produce a working screenshot tool. Only one of them requires you to trust the developer indefinitely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The permissions you will see, in plain terms
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;What it allows&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeTab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read and script the current tab&lt;/td&gt;
&lt;td&gt;Only after you click the extension, only that tab, only until you navigate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;all_urls&amp;gt;&lt;/code&gt; / &lt;code&gt;host_permissions&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Read and script pages&lt;/td&gt;
&lt;td&gt;Every matching site, all the time, without any click&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scripting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inject the code that does the scrolling and measuring&lt;/td&gt;
&lt;td&gt;Only where the extension already has access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;downloads&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write the finished file to your downloads folder&lt;/td&gt;
&lt;td&gt;Files the extension creates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;storage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remember your settings&lt;/td&gt;
&lt;td&gt;Local to the extension&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tabs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;See the URL and title of every open tab&lt;/td&gt;
&lt;td&gt;All tabs, all the time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The two rows that matter are the broad host permission and &lt;code&gt;tabs&lt;/code&gt;. Everything else on that list is narrow and boring. Those two are what turn “a tool that photographs a page when I ask it to” into “a program with a standing view of my browsing”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why so many screenshot extensions ask for everything
&lt;/h2&gt;

&lt;p&gt;Rarely malice; usually convenience. Building on &lt;code&gt;activeTab&lt;/code&gt; means the extension has no access until the user clicks, which rules out anything that wants to act before the click — preloading a content script on every page, watching for navigation, showing a badge that reflects page state. A broad host permission makes all of that trivial, and it is one line in the manifest.&lt;/p&gt;

&lt;p&gt;It also makes analytics and monetisation easier later, which is the part worth being alert about. The permission is requested once, at install; what it is used for can change with any update, and updates install silently. Several widely-installed extensions have been sold to new owners and quietly repurposed exactly this way — the users never re-approved anything, because nothing new was asked for.&lt;/p&gt;

&lt;p&gt;This is why the permission list matters more than the privacy policy. The policy describes intent today; the permission describes capability for as long as the extension is installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check a listing before installing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;On the store page, open the &lt;strong&gt;Privacy practices&lt;/strong&gt; section and read the
permission list, not just the summary sentence.&lt;/li&gt;
&lt;li&gt;Look for a broad host permission. “on all sites” or “on every website
you visit” is the phrase to notice.&lt;/li&gt;
&lt;li&gt;Check whether it asks for &lt;code&gt;tabs&lt;/code&gt;. A screenshot tool does not need to know what
else is open.&lt;/li&gt;
&lt;li&gt;After installing, open the extension’s details page and set site access to
&lt;em&gt;On click&lt;/em&gt; if the option is available. Most extensions still work.&lt;/li&gt;
&lt;li&gt;If the source is public, read the manifest yourself — it is a short file and the
permission list is at the top.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What OpenCapture requests
&lt;/h2&gt;

&lt;p&gt;Four permissions, and no broad host permission at all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;activeTab&lt;/code&gt; — access to the tab you are on, granted by your click and
dropped when you leave.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scripting&lt;/code&gt; — to inject the capture routine into that tab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;downloads&lt;/code&gt; — to save the finished image or PDF.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;storage&lt;/code&gt; — to remember your settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is no &lt;code&gt;&amp;lt;all_urls&amp;gt;&lt;/code&gt; and no &lt;code&gt;tabs&lt;/code&gt;. The only host permissions in the manifest are &lt;em&gt;optional&lt;/em&gt; and limited to two OpenCapture domains, requested only if you choose to buy credits for the optional tiled-watermark feature; decline them and the capture, editing and export features are unaffected, because none of them involve a network at all — the stitching and image processing run locally in a Rust/WebAssembly core.&lt;/p&gt;

&lt;p&gt;You do not have to take that on trust. The manifest is in the public repository, the extension is AGPL-3.0, and the permission list on the store page is the same four entries.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the permissions cannot tell you
&lt;/h2&gt;

&lt;p&gt;Being honest about the limits: a narrow permission set constrains what an extension is able to do, but it does not prove what it does with the access it has. &lt;code&gt;activeTab&lt;/code&gt; still means that on the tab you clicked, at that moment, the extension can read the page. The guarantees worth looking for are cumulative — narrow permissions, public source, a verifiable build, and no network calls in the capture path. Any one of them alone is weaker than it sounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why does a screenshot extension need to read all my data on all websites?
&lt;/h3&gt;

&lt;p&gt;It usually does not. Capturing a full page requires running code in the page, but &lt;code&gt;activeTab&lt;/code&gt; grants that for the current tab on click. A broad host permission is a convenience for the developer, not a requirement of the feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does activeTab actually allow?
&lt;/h3&gt;

&lt;p&gt;Reading and scripting the tab you are on, granted when you click the extension and revoked when you navigate away. It gives no access to other tabs and no access before the click.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I restrict an extension that already asks for everything?
&lt;/h3&gt;

&lt;p&gt;Yes. On the extension’s details page, set site access to “On click”. Many extensions keep working; the ones that break were relying on background access.&lt;/p&gt;

&lt;h3&gt;
  
  
  What permissions does OpenCapture request?
&lt;/h3&gt;

&lt;p&gt;activeTab, scripting, downloads and storage — no broad host permission and no tabs permission. Two optional host permissions cover the paid credit purchase only.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chromewebstore.google.com/detail/full-page-screenshot-to-p/ikhhoggnlncjhpdbnneekifbnmojpjph" rel="noopener noreferrer"&gt;Add to Chrome&lt;/a&gt; &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/opencapture-full-page-capture/" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt; &lt;a href="https://microsoftedge.microsoft.com/addons/detail/full-page-screenshot-to-p/nbblbelngcbfijhifmbjcoehocngplpc" rel="noopener noreferrer"&gt;Edge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free. No account required. Nothing is uploaded.&lt;/p&gt;

&lt;p&gt;Related&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/private-screenshot-extension.html" rel="noopener noreferrer"&gt;Why nothing about the page is uploaded&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/blog/blur-sensitive-information-screenshots.html" rel="noopener noreferrer"&gt;Blurring sensitive information, and when blur is not enough&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/blog/browser-built-in-vs-extension-screenshots.html" rel="noopener noreferrer"&gt;The browser already does this — when do you need an extension?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/faq.html" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>webdev</category>
      <category>browser</category>
    </item>
    <item>
      <title>Blurring sensitive information in a screenshot — and when it is not enough</title>
      <dc:creator>OpenCapture</dc:creator>
      <pubDate>Thu, 08 Oct 2026 15:46:20 +0000</pubDate>
      <link>https://dev.to/opencapture/blurring-sensitive-information-in-a-screenshot-and-when-it-is-not-enough-28hn</link>
      <guid>https://dev.to/opencapture/blurring-sensitive-information-in-a-screenshot-and-when-it-is-not-enough-28hn</guid>
      <description>&lt;p&gt;Blur is the default redaction tool everywhere, and for most things it is fine. For short, predictable text — an order number, a six-digit code, an email address on a known domain — it is weaker than almost anyone assumes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; Blur and pixelation are reversible in principle: the original pixels are averaged, not removed, and short text drawn from a small set of possibilities can often be recovered by trying candidates until one blurs to the same result. For anything that actually matters, cover it with a &lt;strong&gt;solid block&lt;/strong&gt;, and make sure the redaction is applied to the pixels before the file is saved — not as a layer or an overlay that can be peeled off.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F01xhwj4bb856iz1660cj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F01xhwj4bb856iz1660cj.webp" alt="A log excerpt before and after blurring: the account ID, recipient address and signing key are replaced with blurred pixels in the exported PNG" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same log before and after. In the exported file the source pixels are gone, not covered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two ways a redaction fails
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The redaction was never in the image
&lt;/h3&gt;

&lt;p&gt;This is the common one and the more embarrassing. Some tools draw the black box as an object in a document, a layer in a file format, or a CSS overlay in a preview. Export or open that file in something else and the box moves, or is simply removed, and the original is underneath. It has happened to law firms, government departments and newspapers, repeatedly.&lt;/p&gt;

&lt;p&gt;A blurring is only real if the pixels underneath were destroyed at export time. If you can select, move or delete the box after the fact, you have covered the data, not removed it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The blur was reversible
&lt;/h3&gt;

&lt;p&gt;This one is less obvious. A Gaussian blur is a deterministic averaging of neighbouring pixels. Pixelation is the same idea with bigger blocks. Neither adds information and neither destroys as much as it appears to.&lt;/p&gt;

&lt;p&gt;If an attacker knows roughly what the text is — a numeric code, a date, a name from a known list, a URL on a known domain — they can render every candidate in the same font at the same size, apply the same blur, and compare. The match is usually unambiguous. This works because the search space is small, not because the blur was done badly.&lt;/p&gt;

&lt;p&gt;The practical rule: blur is fine for things that are merely &lt;em&gt;noisy&lt;/em&gt; — other people’s avatars, unrelated rows in a table, a busy sidebar. It is not fine for things that are &lt;em&gt;secret&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to use for what
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API key, session token, password&lt;/td&gt;
&lt;td&gt;Solid block&lt;/td&gt;
&lt;td&gt;High value, and often short enough to brute-force from a blur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Card number, bank details&lt;/td&gt;
&lt;td&gt;Solid block&lt;/td&gt;
&lt;td&gt;Fixed format, very small search space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email address, customer name&lt;/td&gt;
&lt;td&gt;Solid block&lt;/td&gt;
&lt;td&gt;Usually drawn from a guessable set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Faces of uninvolved people&lt;/td&gt;
&lt;td&gt;Blur is acceptable&lt;/td&gt;
&lt;td&gt;Goal is de-emphasis, not secrecy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unrelated content around the point&lt;/td&gt;
&lt;td&gt;Blur, or crop&lt;/td&gt;
&lt;td&gt;Reducing noise, nothing to protect&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Things people forget to blur
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The URL.&lt;/strong&gt; Tokens, session IDs and internal hostnames live there, and the
address bar is in every screenshot of a browser window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser tabs.&lt;/strong&gt; Tab titles leak project names, customer names and what else
you were doing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifications.&lt;/strong&gt; A toast or a system banner that appeared mid-capture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autocomplete dropdowns.&lt;/strong&gt; Opened over the field you were demonstrating.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The window title bar and taskbar.&lt;/strong&gt; Usernames and machine names.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflections and second monitors&lt;/strong&gt; in photographs of screens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A quick habit that catches most of these: before sharing, look at the image once from the outside in — edges first, content last. The leaks are almost always at the edges, because that is where you were not looking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metadata is part of the file
&lt;/h2&gt;

&lt;p&gt;An exported image can carry more than pixels. Screenshots taken by some tools embed the source URL, the window title, a timestamp or the device name in EXIF or PNG text chunks. If you have blurred the URL from the image but it is still in the metadata, you have not blurred it. Strip metadata on export, or check the file before it goes anywhere public.&lt;/p&gt;

&lt;h2&gt;
  
  
  A routine that holds up
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Capture the page, then blur &lt;em&gt;before&lt;/em&gt; saving — not after, and not in a second
tool.&lt;/li&gt;
&lt;li&gt;Use solid fill for anything secret; reserve blur for de-emphasis.&lt;/li&gt;
&lt;li&gt;Sweep the edges: URL bar, tabs, title bar, notifications, taskbar.&lt;/li&gt;
&lt;li&gt;Export, then reopen the exported file and confirm the blurring is baked into the pixels
and nothing sits under it.&lt;/li&gt;
&lt;li&gt;Check the file’s metadata if it is going anywhere public.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How OpenCapture handles it
&lt;/h2&gt;

&lt;p&gt;Blur and solid-block blurring are applied to the pixels in the editor, and the export is flattened — there is no separate layer to remove and nothing underneath to recover. All of it runs locally in a Rust/WebAssembly core, so a screenshot containing customer data is never uploaded anywhere in order to be edited, which matters more than the blurring tool itself if the image is sensitive in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can blurred text in a screenshot be recovered?
&lt;/h3&gt;

&lt;p&gt;Often, yes, when the text is short and predictable. Blur averages pixels rather than removing them, so candidates can be rendered, blurred the same way and compared until one matches. Use a solid block for anything secret.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is pixelation safer than blur?
&lt;/h3&gt;

&lt;p&gt;No. Pixelation is the same averaging with larger blocks, and is subject to the same candidate-matching attack.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the safest way to hide information in a screenshot?
&lt;/h3&gt;

&lt;p&gt;Cover it with a solid, opaque block, flatten the image on export so nothing sits underneath, and strip the file’s metadata before sharing.&lt;/p&gt;

&lt;h3&gt;
  
  
  What do people most often forget to blur?
&lt;/h3&gt;

&lt;p&gt;The edges of the image: the URL bar, tab titles, notifications, the taskbar and the window title. Content gets checked; edges do not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chromewebstore.google.com/detail/full-page-screenshot-to-p/ikhhoggnlncjhpdbnneekifbnmojpjph" rel="noopener noreferrer"&gt;Add to Chrome&lt;/a&gt; &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/opencapture-full-page-capture/" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt; &lt;a href="https://microsoftedge.microsoft.com/addons/detail/full-page-screenshot-to-p/nbblbelngcbfijhifmbjcoehocngplpc" rel="noopener noreferrer"&gt;Edge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free. No account required. Nothing is uploaded.&lt;/p&gt;

&lt;p&gt;Related&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/blog/screenshots-for-bug-reports.html" rel="noopener noreferrer"&gt;Screenshots for bug reports: what to capture, what to blur&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/blog/screenshot-extension-permissions.html" rel="noopener noreferrer"&gt;What permissions a screenshot extension asks for&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/private-screenshot-extension.html" rel="noopener noreferrer"&gt;Why nothing about the page is uploaded&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/faq.html" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Your browser already takes full-page screenshots. When do you actually need an extension?</title>
      <dc:creator>OpenCapture</dc:creator>
      <pubDate>Thu, 08 Oct 2026 15:45:38 +0000</pubDate>
      <link>https://dev.to/opencapture/your-browser-already-takes-full-page-screenshots-when-do-you-actually-need-an-extension-4b5</link>
      <guid>https://dev.to/opencapture/your-browser-already-takes-full-page-screenshots-when-do-you-actually-need-an-extension-4b5</guid>
      <description>&lt;p&gt;Chrome, Firefox and Edge can all capture a whole scrolling page with no extension installed. Almost nobody knows the Chrome one exists, because it is buried in DevTools. Here is how to use each — and an honest account of where they stop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; For a one-off PNG of a page, use the browser. It is free, already installed, and there is nothing to trust. An extension earns its place when you need the things the built-in feature does not do at all: &lt;strong&gt;annotation&lt;/strong&gt;, &lt;strong&gt;blurring&lt;/strong&gt;, &lt;strong&gt;PDF export&lt;/strong&gt;, and correct handling of pages long enough to hit the canvas ceiling.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to do it without installing anything
&lt;/h2&gt;

&lt;p&gt;All three can already do it. Firefox puts it in the right-click menu — &lt;em&gt;Take Screenshot&lt;/em&gt;, then &lt;em&gt;Save full page&lt;/em&gt;. Edge has Web capture on &lt;code&gt;Ctrl&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;S&lt;/code&gt;, with a pen and an eraser afterwards. Chrome has no menu entry at all; the command lives in the developer tools.&lt;/p&gt;

&lt;p&gt;The step-by-step for each, with screenshots and the gotchas at the save step, is in &lt;a href="https://opencapture.app/how-to/scrolling-screenshot-desktop.html" rel="noopener noreferrer"&gt;how to take a scrolling screenshot on desktop&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the built-in features stop
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Chrome DevTools&lt;/th&gt;
&lt;th&gt;Firefox&lt;/th&gt;
&lt;th&gt;Edge Web capture&lt;/th&gt;
&lt;th&gt;Dedicated tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full-page PNG&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discoverable&lt;/td&gt;
&lt;td&gt;No — DevTools only&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Annotation&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Pen only&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blurring / blur&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF export&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Very long pages&lt;/td&gt;
&lt;td&gt;Truncates or fails&lt;/td&gt;
&lt;td&gt;Warns and caps&lt;/td&gt;
&lt;td&gt;Caps&lt;/td&gt;
&lt;td&gt;Splits or paginates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handles lazy images&lt;/td&gt;
&lt;td&gt;Partly&lt;/td&gt;
&lt;td&gt;Partly&lt;/td&gt;
&lt;td&gt;Partly&lt;/td&gt;
&lt;td&gt;Waits for them&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last two rows are where the difference is real rather than cosmetic. Every browser caps canvas size — on Chrome, 32,767px on one dimension — and past that limit the built-in capture does not warn you clearly; it hands back an image that is truncated or blank. On a long documentation page or a social feed, that is easy to hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The other difference: what happens next
&lt;/h2&gt;

&lt;p&gt;The built-in tools give you a file and stop. That is a feature if all you wanted was the file. It becomes friction the moment the screenshot has a job to do — going into a ticket with an arrow on it, into a document with a customer name covered, into an email as a PDF that keeps the layout.&lt;/p&gt;

&lt;p&gt;At that point the built-in route becomes: capture, open an image editor, annotate, blur, export, convert. Three tools instead of one, and the blurring step happens somewhere you have to think about, rather than before the file was ever written.&lt;/p&gt;

&lt;p&gt;Worth saying plainly: if you take a screenshot once a month and paste it straight into a chat, the browser’s own feature is the right answer and an extension is overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check before installing anything
&lt;/h2&gt;

&lt;p&gt;The cost of an extension is not the download; it is the access. A full-page capture tool has to run code inside the page, and there are two ways to be granted that — narrowly, on click, for one tab, or broadly, for every site you visit, permanently. Most ask for the broad version. Check the permission list on the store page before installing; there is a fuller explanation in &lt;a href="https://opencapture.app/blog/screenshot-extension-permissions.html" rel="noopener noreferrer"&gt;the piece on permissions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where OpenCapture sits
&lt;/h2&gt;

&lt;p&gt;OpenCapture does the four things the built-in features do not: annotation, solid-block and blur blurring, PDF export, and long pages split or paginated instead of truncated. It asks for &lt;code&gt;activeTab&lt;/code&gt; rather than access to every site, and the capture, editing and export all run locally in a Rust/WebAssembly core, so nothing about the page is uploaded. It is free and open source; the only paid element is an optional tiled-watermark feature ($5 for 1,000 credits, once).&lt;/p&gt;

&lt;p&gt;If none of those four things are what you need, use DevTools. That advice costs us an install and it is still the right advice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I take a full-page screenshot in Chrome without an extension?
&lt;/h3&gt;

&lt;p&gt;Open DevTools, press &lt;code&gt;Ctrl&lt;/code&gt;+&lt;code&gt;Shift&lt;/code&gt;+&lt;code&gt;P&lt;/code&gt;, type &lt;code&gt;screenshot&lt;/code&gt; and choose &lt;em&gt;Capture full size screenshot&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I take a full-page screenshot in Firefox?
&lt;/h3&gt;

&lt;p&gt;Right-click the page, choose &lt;em&gt;Take Screenshot&lt;/em&gt;, then &lt;em&gt;Save full page&lt;/em&gt;. The &lt;a href="https://opencapture.app/how-to/full-page-screenshot-firefox.html" rel="noopener noreferrer"&gt;Firefox guide&lt;/a&gt; has the screenshots and the three limits of that tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did Chrome’s built-in full-page screenshot come out blank or cut off?
&lt;/h3&gt;

&lt;p&gt;The page exceeded the browser’s canvas limit — 32,767px on one dimension on Chrome. Past that, drawing silently fails. Tools built for long pages split the output into segments instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need a screenshot extension at all?
&lt;/h3&gt;

&lt;p&gt;Only if you need annotation, blurring, PDF export, or pages long enough to break the built-in capture. For a one-off PNG, the browser’s own feature is enough.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chromewebstore.google.com/detail/full-page-screenshot-to-p/ikhhoggnlncjhpdbnneekifbnmojpjph" rel="noopener noreferrer"&gt;Add to Chrome&lt;/a&gt; &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/opencapture-full-page-capture/" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt; &lt;a href="https://microsoftedge.microsoft.com/addons/detail/full-page-screenshot-to-p/nbblbelngcbfijhifmbjcoehocngplpc" rel="noopener noreferrer"&gt;Edge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free. No account required. Nothing is uploaded.&lt;/p&gt;

&lt;p&gt;Related&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/blog/how-full-page-screenshots-work.html" rel="noopener noreferrer"&gt;How full-page screenshots work — and why they break&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/blog/screenshot-extension-permissions.html" rel="noopener noreferrer"&gt;What permissions a screenshot extension asks for&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/webpage-to-pdf.html" rel="noopener noreferrer"&gt;Webpage to PDF, with the page still looking like the page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/alternatives.html" rel="noopener noreferrer"&gt;Alternatives compared&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>chrome</category>
      <category>firefox</category>
    </item>
    <item>
      <title>How full-page screenshots actually work — and the four ways they break</title>
      <dc:creator>OpenCapture</dc:creator>
      <pubDate>Thu, 08 Oct 2026 15:44:46 +0000</pubDate>
      <link>https://dev.to/opencapture/how-full-page-screenshots-actually-work-and-the-four-ways-they-break-4odp</link>
      <guid>https://dev.to/opencapture/how-full-page-screenshots-actually-work-and-the-four-ways-they-break-4odp</guid>
      <description>&lt;p&gt;A browser can only ever photograph the part of a page currently on screen. Every “full page” screenshot is therefore several photographs glued together — and almost all of the interesting bugs live in the glue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; Capture scrolls the page, photographs each viewport, and stitches the slices onto one canvas. Four things go wrong: &lt;strong&gt;sticky headers&lt;/strong&gt; repeat in every slice, &lt;strong&gt;lazy images&lt;/strong&gt; get photographed before they load, &lt;strong&gt;inner scroll regions&lt;/strong&gt; are never scrolled at all, and &lt;strong&gt;device-pixel rounding&lt;/strong&gt; leaves hairlines at every seam. There is a one-minute test further down that catches all four.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop, and exactly where it breaks
&lt;/h2&gt;

&lt;p&gt;Strip away the details and every implementation is the same four steps, repeated until you reach the bottom of the document:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scroll to the next vertical offset.&lt;/li&gt;
&lt;li&gt;Photograph whatever is currently visible — that is one &lt;em&gt;slice&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Advance the offset by one viewport height.&lt;/li&gt;
&lt;li&gt;Draw every slice onto a single canvas, in order, and export it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Write that and you will have something working in an afternoon. Point it at a real website and it falls apart within about thirty seconds, in four distinct ways. Each has a recognisable symptom, so once you know them you can tell at a glance which one you are looking at.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The navigation bar appears six times
&lt;/h2&gt;

&lt;p&gt;An element with &lt;code&gt;position: sticky&lt;/code&gt; or &lt;code&gt;position: fixed&lt;/code&gt; stays glued to the viewport, which means it is present in &lt;em&gt;every&lt;/em&gt; slice. Stitch them and the header marches down the finished image like a flipbook, with the real content sliced up between the repetitions.&lt;/p&gt;

&lt;p&gt;The fix is to hide those elements for the duration of the capture and restore them afterwards. It sounds obvious; a surprising number of tools skip it. The same applies to cookie banners, chat bubbles, newsletter popups and back-to-top buttons.&lt;/p&gt;

&lt;p&gt;Hiding everything with &lt;code&gt;position: fixed&lt;/code&gt; is too blunt. A sticky header is genuinely part of the page and should appear once, at the top, where it belongs.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Half the images are grey boxes
&lt;/h2&gt;

&lt;p&gt;Images that load when they enter the viewport need a moment to arrive. Scroll, capture and scroll again with no pause and you photograph the placeholder instead of the picture.&lt;/p&gt;

&lt;p&gt;This is the most common cause of a screenshot that looks obviously wrong to a human but is hard to describe. The page looked fine while you were reading it, because you scrolled at human speed and everything had time to load.&lt;/p&gt;

&lt;p&gt;A correct implementation scrolls, waits for the network and layout to settle, and only then captures. That is slower — which is exactly why not everything does it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The table only shows four rows
&lt;/h2&gt;

&lt;p&gt;A page can contain its own scrolling regions: a data table with a fixed height, a code block, a chat panel, a sidebar with &lt;code&gt;overflow: auto&lt;/code&gt;. Those are separate scroll contexts. A full-page capture scrolls the &lt;em&gt;document&lt;/em&gt;; it does not scroll them.&lt;/p&gt;

&lt;p&gt;So the outer page comes out complete while the inner region shows only whatever happened to be visible. There is no universal fix — a tool has to detect scrollable descendants and decide what to do about each one, and very few do. Worth knowing so you can spot it rather than assume the capture is complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Thin lines of duplicated pixels at every seam
&lt;/h2&gt;

&lt;p&gt;This one produces the strangest artefacts. On a HiDPI display the browser renders at 2× or 3×. Scroll offsets are expressed in CSS pixels; the captured bitmap is in device pixels. Mix the two anywhere in the arithmetic and every slice lands a fraction off.&lt;/p&gt;

&lt;p&gt;The result is a hairline of duplicated or missing pixels at each boundary. You usually notice it first as text that looks subtly wrong — a line of type carrying a sliver of the line above it. Zoom to 400% at a boundary and it is unmistakable.&lt;/p&gt;

&lt;p&gt;The arithmetic that matters: a slice’s destination has to be computed as &lt;code&gt;round(index × viewportHeight × devicePixelRatio)&lt;/code&gt;, in device pixels. Using the CSS-pixel height directly is what puts the hairlines there.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fifth problem, on very long pages only
&lt;/h2&gt;

&lt;p&gt;Browsers cap how large a single canvas surface can be. On Chrome that is 32,767px on any one dimension, with a total area ceiling of 268,435,456px. Exceeding either does not raise an error — the canvas silently becomes unusable and draw calls turn into no-ops, so you get a blank or truncated image with nothing in the console to explain it.&lt;/p&gt;

&lt;p&gt;Anything that captures genuinely long pages therefore has to split the output into segments rather than allocating one enormous surface. In practice that means a very tall capture arrives as several PNGs, or as a multi-page PDF.&lt;/p&gt;

&lt;h2&gt;
  
  
  A one-minute test for any tool
&lt;/h2&gt;

&lt;p&gt;Find a page with a sticky header, lazy images, an inner scroll region and roughly 8,000 pixels of height — most documentation sites qualify. Capture it, then check four things:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;What a failure looks like&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Header count&lt;/td&gt;
&lt;td&gt;The nav bar appears more than once&lt;/td&gt;
&lt;td&gt;Sticky elements not hidden&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Images below the fold&lt;/td&gt;
&lt;td&gt;Grey placeholder boxes&lt;/td&gt;
&lt;td&gt;No wait for lazy loading&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inner regions&lt;/td&gt;
&lt;td&gt;A table showing only the rows that were on screen&lt;/td&gt;
&lt;td&gt;Nested scroll context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seams at 400% zoom&lt;/td&gt;
&lt;td&gt;Thin repeated or missing lines&lt;/td&gt;
&lt;td&gt;CSS vs device pixel rounding&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A tool that survives that will survive your actual work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the browser’s built-in feature sits
&lt;/h2&gt;

&lt;p&gt;Both Chrome and Firefox can already do this without an extension. In Chrome, open DevTools, press &lt;code&gt;Ctrl&lt;/code&gt;+&lt;code&gt;Shift&lt;/code&gt;+&lt;code&gt;P&lt;/code&gt;, type &lt;code&gt;screenshot&lt;/code&gt; and choose &lt;em&gt;Capture full size screenshot&lt;/em&gt;. In &lt;a href="https://opencapture.app/how-to/full-page-screenshot-firefox.html" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt;, right-click the page and choose &lt;em&gt;Take Screenshot&lt;/em&gt; → &lt;em&gt;Save full page&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It gives you a PNG and nothing else — no annotation, no blurring, no PDF — and it is not especially careful about the failure modes above. For a lot of people that is genuinely enough, and it is worth knowing before you install anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  How OpenCapture handles each of these
&lt;/h2&gt;

&lt;p&gt;OpenCapture hides sticky and fixed elements for the duration of the capture and restores them afterwards, waits for lazy content to settle before each slice, and computes every slice offset in device pixels so seams stay pixel-exact across device pixel ratios. Captures longer than the canvas ceiling are split automatically into multiple images, or paginated into a PDF. Stitching and all image processing run locally in a Rust/WebAssembly core — nothing about the page is uploaded anywhere.&lt;/p&gt;

&lt;p&gt;Nested scroll containers remain the one case no tool solves universally. The section above tells you how to spot it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why does my screenshot show the navigation bar several times?
&lt;/h3&gt;

&lt;p&gt;The tool captured each viewport without hiding elements that use &lt;code&gt;position: sticky&lt;/code&gt; or &lt;code&gt;position: fixed&lt;/code&gt;, so the header appears in every slice and repeats down the stitched image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are images below the fold grey boxes?
&lt;/h3&gt;

&lt;p&gt;Lazy-loaded images had not finished arriving when the slice was captured. A tool that waits for the network and layout to settle before each capture avoids this.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the thin lines running across my stitched screenshot?
&lt;/h3&gt;

&lt;p&gt;Seam artefacts caused by mixing CSS pixels with device pixels when computing scroll offsets. They are most visible on HiDPI displays, where the browser renders at 2× or 3×.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did a very long page come back as several images?
&lt;/h3&gt;

&lt;p&gt;Browsers cap the size of a single canvas — on Chrome, 32,767px on one dimension and 268,435,456px of total area. Past that the canvas silently stops working, so long captures are split into segments or paginated into a PDF.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chromewebstore.google.com/detail/full-page-screenshot-to-p/ikhhoggnlncjhpdbnneekifbnmojpjph" rel="noopener noreferrer"&gt;Add to Chrome&lt;/a&gt; &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/opencapture-full-page-capture/" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt; &lt;a href="https://microsoftedge.microsoft.com/addons/detail/full-page-screenshot-to-p/nbblbelngcbfijhifmbjcoehocngplpc" rel="noopener noreferrer"&gt;Edge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free. No account required. Nothing is uploaded.&lt;/p&gt;

&lt;p&gt;Related&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/blog/browser-built-in-vs-extension-screenshots.html" rel="noopener noreferrer"&gt;The browser already does this — when do you need an extension?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/blog/screenshots-for-bug-reports.html" rel="noopener noreferrer"&gt;Screenshots for bug reports: what to capture, what to blur&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/webpage-to-pdf.html" rel="noopener noreferrer"&gt;Webpage to PDF, with the page still looking like the page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencapture.app/faq.html" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>css</category>
      <category>browser</category>
    </item>
    <item>
      <title>Eight things in your frontend that make your app impossible to screenshot</title>
      <dc:creator>OpenCapture</dc:creator>
      <pubDate>Fri, 04 Sep 2026 07:58:50 +0000</pubDate>
      <link>https://dev.to/opencapture/eight-things-in-your-frontend-that-make-your-app-impossible-to-screenshot-39fo</link>
      <guid>https://dev.to/opencapture/eight-things-in-your-frontend-that-make-your-app-impossible-to-screenshot-39fo</guid>
      <description>&lt;p&gt;Someone eventually tries to capture your app. A user filing a bug, a support agent writing a ticket, a PM building a deck, a customer archiving an invoice. They press whatever full-page screenshot tool they have, and they get something wrong: a nav bar repeated nine times, a table with six rows in it, a page that is mostly grey boxes.&lt;/p&gt;

&lt;p&gt;They will not file that as a bug against you. They will just send the broken image, and whoever receives it will misunderstand the problem.&lt;/p&gt;

&lt;p&gt;Full-page capture works by scrolling the document, photographing the viewport at each step, and stitching the slices together. Almost everything below is a case where that loop sees something different from what a human sees.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. &lt;code&gt;position: fixed&lt;/code&gt; and &lt;code&gt;position: sticky&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A fixed header is present in every slice, so it appears once per viewport height in the stitched image. Sticky is the same story with extra edge cases at its stuck/unstuck boundary.&lt;/p&gt;

&lt;p&gt;Good capture tools detach these for the duration and put them back. Not all of them do, and none of them can guess which of your elements is decorative chrome and which is content.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Virtualized lists
&lt;/h2&gt;

&lt;p&gt;This is the one that cannot be worked around from outside.&lt;/p&gt;

&lt;p&gt;If you render 20 of 10,000 rows and swap them as the user scrolls - react-window, TanStack Virtual, ag-grid, your own implementation - then rows 21 through 10,000 &lt;strong&gt;do not exist in the DOM at any moment&lt;/strong&gt;. There is no scroll position at which they can be photographed. A capture of your table is a capture of whatever was mounted.&lt;/p&gt;

&lt;p&gt;Nothing on the tool side fixes this. The page has to offer a non-virtualized rendering path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// something a capture tool or a user can actually reach&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;render=full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;virtualizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOptions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;overscan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even a "print view" that renders everything is enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Lazy-loaded images
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;IntersectionObserver&lt;/code&gt; fires when the image enters the viewport, then the image has to arrive over the network and lay out. A capture loop that scrolls and photographs immediately wins that race and records the placeholder.&lt;/p&gt;

&lt;p&gt;The tool should wait. Many don't, and some can't tell the difference between "still loading" and "intentionally blank".&lt;/p&gt;

&lt;p&gt;Native &lt;code&gt;loading="lazy"&lt;/code&gt; behaves better here than a hand-rolled observer, because browsers already pre-load nearby images and print paths know about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Inner scroll containers
&lt;/h2&gt;

&lt;p&gt;A capture scrolls the &lt;em&gt;document&lt;/em&gt;. A &lt;code&gt;div&lt;/code&gt; with &lt;code&gt;overflow: auto&lt;/code&gt; is a separate scroll context, and it is not the document.&lt;/p&gt;

&lt;p&gt;So the page around it captures fully, and the panel inside it captures whatever slice happened to be visible. Code blocks with &lt;code&gt;max-height&lt;/code&gt;, chat panes, data tables with a frozen header, sidebars - all of them silently truncate.&lt;/p&gt;

&lt;p&gt;If a region is content rather than a viewport-sized widget, consider letting it grow and letting the page scroll instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;code&gt;100vh&lt;/code&gt; app shells
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.app&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;overflow-y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a completely normal layout, and it means your document never scrolls. From the outside, your entire application is one viewport tall. A full-page capture of it returns one screen - correctly, because that &lt;em&gt;is&lt;/em&gt; the whole document.&lt;/p&gt;

&lt;p&gt;Everything real is inside &lt;code&gt;.main&lt;/code&gt;, which is case 4.&lt;/p&gt;

&lt;p&gt;I ran into this building a demo page for a capture tool: the page had a sticky sidebar and a viewport-height shell, and captures of it kept coming out with a 1,400px empty column. The page was fine. The layout was just not a document.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;code&gt;scroll-behavior: smooth&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Set globally, it turns every programmatic &lt;code&gt;scrollTo&lt;/code&gt; into an animation. A capture loop that scrolls and immediately photographs gets a frame from the middle of the animation, and every slice lands at the wrong offset.&lt;/p&gt;

&lt;p&gt;Scope it to user-initiated navigation rather than applying it to &lt;code&gt;html&lt;/code&gt; unconditionally, or respect the reduced-motion query, which most capture paths and many users share:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;no-preference&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;scroll-behavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;smooth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Scroll-triggered animation
&lt;/h2&gt;

&lt;p&gt;Fade-in-on-scroll means an element's opacity depends on when it was observed. During a fast programmatic scroll, some elements are caught mid-transition and some never trigger at all. The stitched image gets a page with randomly half-faded sections.&lt;/p&gt;

&lt;p&gt;Same reduced-motion escape hatch applies.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Canvas and WebGL
&lt;/h2&gt;

&lt;p&gt;A WebGL context created without &lt;code&gt;preserveDrawingBuffer: true&lt;/code&gt; may be cleared before anything outside the render loop can read it, so it can come back blank or stale depending on the capture path. If a chart matters to your users, it is worth checking what it looks like in a capture rather than assuming.&lt;/p&gt;




&lt;h2&gt;
  
  
  A test that takes one minute
&lt;/h2&gt;

&lt;p&gt;Open your own app. Use the built-in browser feature - no extension needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chrome:&lt;/strong&gt; DevTools, Ctrl+Shift+P, type &lt;code&gt;screenshot&lt;/code&gt;, choose &lt;em&gt;Capture full size screenshot&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firefox:&lt;/strong&gt; right-click the page, &lt;em&gt;Take Screenshot&lt;/em&gt; -&amp;gt; &lt;em&gt;Save full page&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then check four things:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Failure looks like&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Header count&lt;/td&gt;
&lt;td&gt;Nav bar appears more than once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image content&lt;/td&gt;
&lt;td&gt;Grey placeholders below the fold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long lists&lt;/td&gt;
&lt;td&gt;A table with only the visible rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page height&lt;/td&gt;
&lt;td&gt;The capture is exactly one screen tall&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If the last row is true, you have case 5 and everything else is moot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why bother
&lt;/h2&gt;

&lt;p&gt;Screenshots of your product are how it gets described to people who have not used it - in bug reports, in internal decks, in support threads, in a review someone posts. If those images are broken, the description is broken, and you are not in the room to correct it.&lt;/p&gt;

&lt;p&gt;Fixing this is mostly not new code. It is a print/export path, one query parameter that disables virtualization, and not putting &lt;code&gt;scroll-behavior: smooth&lt;/code&gt; on &lt;code&gt;html&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written while working on &lt;a href="https://opencapture.app" rel="noopener noreferrer"&gt;OpenCapture&lt;/a&gt;, a free and open-source (AGPL-3.0) full-page screenshot extension for Chrome, Firefox and Edge. Source is on &lt;a href="https://github.com/Open-Capture/OpenCapture" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; if you want to see how any of the above is handled in practice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>frontend</category>
      <category>ux</category>
    </item>
    <item>
      <title>Better bug reports: what to screenshot, and what to hide first</title>
      <dc:creator>OpenCapture</dc:creator>
      <pubDate>Thu, 03 Sep 2026 06:17:42 +0000</pubDate>
      <link>https://dev.to/opencapture/better-bug-reports-what-to-screenshot-and-what-to-hide-first-51li</link>
      <guid>https://dev.to/opencapture/better-bug-reports-what-to-screenshot-and-what-to-hide-first-51li</guid>
      <description>&lt;p&gt;Most bug reports contain a screenshot. Most of those screenshots are either not enough to reproduce the problem, or contain something that should not have left the building.&lt;/p&gt;

&lt;p&gt;Both are fixable in about thirty seconds each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capture more than the error
&lt;/h2&gt;

&lt;p&gt;The instinct is to screenshot the error message. The error message is usually the least informative part of the page.&lt;/p&gt;

&lt;p&gt;What the person fixing it needs is context: the URL, the state of the form, what else was on screen, and — often decisive — the browser console. An error alone tells them what broke. The surrounding page tells them why.&lt;/p&gt;

&lt;p&gt;A full-page capture costs nothing extra and removes an entire round trip of "can you send the whole page?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Include the things you are tempted to crop
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The URL bar.&lt;/strong&gt; Query parameters and path segments are frequently the difference between reproducing a bug and not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timestamps.&lt;/strong&gt; If the page shows one, it lets someone match your report against server logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The console.&lt;/strong&gt; Open DevTools before capturing. A stack trace in the image saves a day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your viewport size.&lt;/strong&gt; Many layout bugs only exist at certain widths. Some tools stamp dimensions on the capture; if not, mention it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then hide the things you are tempted to leave
&lt;/h2&gt;

&lt;p&gt;Bug reports travel further than the person writing them expects. They get pasted into group chats, forwarded to vendors, attached to public issue trackers.&lt;/p&gt;

&lt;p&gt;Before sending, redact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customer names and email addresses&lt;/strong&gt; visible in tables or headers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account and order identifiers&lt;/strong&gt; that map to a real person&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API keys or tokens&lt;/strong&gt; visible in a logged request or a URL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal hostnames&lt;/strong&gt; that reveal infrastructure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anything in an adjacent browser tab&lt;/strong&gt; — tab titles are readable&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Redaction has a failure mode
&lt;/h2&gt;

&lt;p&gt;Two operations are both called blur, and only one of them removes information.&lt;/p&gt;

&lt;p&gt;Some tools draw a blurred overlay while the original pixels remain in the underlying data. Depending on the export, that can sometimes be recovered. Others resample the region and discard the source, which cannot be undone.&lt;/p&gt;

&lt;p&gt;Test yours once: blur a line of text, export, open the export, and push contrast and sharpness hard. If characters start resolving, use a solid box instead of blur for anything that matters.&lt;/p&gt;

&lt;p&gt;Solid boxes are ugly and completely reliable. For a token, take the ugly option.&lt;/p&gt;

&lt;h2&gt;
  
  
  A checklist worth pinning
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Full page, not just the error&lt;/li&gt;
&lt;li&gt;Console open if it is a JavaScript bug&lt;/li&gt;
&lt;li&gt;URL visible&lt;/li&gt;
&lt;li&gt;Redact names, emails, IDs, tokens, internal hostnames&lt;/li&gt;
&lt;li&gt;Check no other tab is readable&lt;/li&gt;
&lt;li&gt;Note the browser and viewport width&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Six items, about a minute, and it removes most of the back-and-forth that makes bug reports slow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure
&lt;/h2&gt;

&lt;p&gt;I work on &lt;a href="https://opencapture.app" rel="noopener noreferrer"&gt;OpenCapture&lt;/a&gt;, an open-source screenshot extension built around this workflow — full page capture, annotation, and a destructive mosaic blur rather than a cosmetic one. But the checklist above works with whatever you already have, including the capture tool already built into your browser.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
