The capture cascade
Screenshots are taken in two stages, and it is worth understanding which one you get, because their fidelity differs.
Stage one — the browser's own screen capture. Pixel-exact: it is a picture of what the screen actually showed, including everything CSS can do. The browser asks the user for permission once per capture, and that prompt is expected behavior, not a failure — it appears only after the user clicks "Capture screenshot", never on page load.
Stage two — the DOM renderer. No permission prompt, works everywhere including iOS Safari, and reconstructs the page from the DOM rather than photographing it. That reconstruction is very good and has named limits, listed under what the DOM stage does not reproduce.
screenshot.strategy picks the behavior:
| Value | Behavior |
|---|---|
auto (default) | try stage one, fall back to stage two when it is unavailable or declined |
native | stage one only |
dom | stage two only — no permission prompt ever |
off | no screenshot button at all |
The report records which stage the reporter's browser says produced the screenshot, as
capture_method (native or dom) in its technical details. Treat it as a hint about what
to expect from the picture, not as proof that the picture is exact: the value comes from the
browser, the server cannot check it against the file, and the report mail marks it as
reported by the browser.
Whatever the stage, the reporter sees the screenshot before sending and can discard or retake it. Nothing is uploaded until they attach it.
Which is why Send is refused while a capture is still sitting in that preview. It exists only in their browser at that point, so sending would file the report without the one thing they took a screenshot for — and the old behavior did exactly that, silently, followed by a success message. The widget now says which of the two ways out there is and puts focus on the Attach button. It does not attach for them: Discard is there because a capture is sometimes deliberately not sent, and choosing on their behalf overrides that.
If you drive the capture component yourself rather than through the shipped widget, that
refusal is a seam you have to fill: onPending sits beside onStage and is called when a
capture starts waiting in the preview, and cleared when it is attached, discarded or fails.
The shipped implementation sets the component's screenshotPending property, which is what
the submit reads. A custom integration that never calls it simply keeps the older behavior,
where Send goes through and the capture is dropped. onEdited is the third seam: it is told
whether the preview shows an edited picture, and the shipped implementation sets
screenshotEdited, which puts the flag described below on the report.
What ends up in the frame
The visible viewport, not the whole page. screenshot.viewport_only is on by default and
both stages honor it, so a report about something further down the page arrives as the band
the reporter was actually looking at. That is usually the point — but it is worth knowing
before you go looking for the rest of the page in the image.
Stage one captures whatever the reporter agreed to share. The browser owns that choice, and this package does not get to make it: Chromium narrows the picker to the current tab, elsewhere the reporter can pick another window or the whole screen, and what they pick is what arrives. Two consequences worth carrying: a report can contain more of their desktop than either of you intended, and region redaction covers regions of your page — it has no reach into a window that is not yours.
Cropping and marking before attaching
The preview offers Edit beside Attach. It opens the capture in an editor where the reporter
crops it: by dragging the handles or the crop itself, with the arrow keys on the crop area (Shift
resizes, Alt moves in single pixels), or by typing the four percentages. Apply puts the cropped
picture in the preview, fitted to screenshot.max_bytes like a capture, and only that picture is
uploaded when they attach it. The uncropped capture never leaves the browser. Cancel and Escape
close the editor without applying, and what was set is still there the next time it opens, until
the capture is discarded or retaken.
The same editor marks what the report is about. Beside Crop it offers an arrow, a line, an ellipse, a rectangle and a freehand line, in five colors and three widths. The reporter draws a mark with the pointer, or presses a tool's button from the keyboard and gets one in the middle of the picture. A press on a mark's stroke selects it, a drag moves it and its handles resize it, and Shift while drawing holds a line to steps of 45 degrees and a box square. Undo and Redo, or Ctrl+Z and Ctrl+Shift+Z, step through every change. Apply draws each mark into the picture with a light seam under its color, so it reads on a dark page and on a light one.
Cropping is the reporter's answer to the paragraph above: a share that took in more of their screen than they meant can be cut down to your page before anything is sent. It removes what lies outside the crop and nothing inside it, and a mark is an outline, so neither is a way to blank out part of the picture. Region redaction is.
A report with an edited screenshot says so: screenshot_edited is true in its technical
details, because a cropped picture no longer matches the viewport the other details describe, and a
marked one shows more than the page did. Like capture_method, it is the browser's statement.
The editor is a file of its own, visual-feedback-editor.iife.js, fetched the first time somebody
presses Edit. Setting screenshot.editor (VISUAL_FEEDBACK_SCREENSHOT_EDITOR) to false takes the
button away, and the file is never fetched. When the file cannot be fetched, the preview says so
and the capture can still be attached as it is.
The byte cap holds on both ends
screenshot.max_bytes (8 MB) is the number the browser fits a capture to and the server
checks it against. A capture over the cap is scaled down in the browser, in up to four passes,
before the preview shows it, so the reporter sees what is sent. The server still refuses one
that does not fit, which only a cap far below what the page can be drawn at reaches. Each pass
costs detail: if your captures are routinely too large, lower screenshot.scale, which sets
the size the browser renders at, rather than the cap.