Review visual changes
A visual review is a decision about whether the current interface is correct. The screenshot diff is evidence; it does not decide for you.
1. Open the build
Open a project and choose a build from the branch or merge request you are reviewing. Builds with changes waiting for a decision show Uploaded or In Review.
Review the newest build on the branch. When a newer build on the same branch finishes uploading, an older build that’s still waiting becomes Superseded and can’t be reviewed any more; see Superseded builds below.
2. Start with the change list
Use the screenshot list to move through the build. Prioritize:
- Changed screenshots, where the current capture differs from the baseline.
- New screenshots, which need their first approved baseline.
- Removed screenshots, where a previously tracked screenshot disappeared. A test that failed or didn’t run also shows up this way, so read Missing screenshots and removals before approving one.
Not changed screenshots need no visual decision. Check their other tabs when the project blocks on performance or accessibility findings: a screenshot can match its baseline within tolerance and still have one. See Findings without a pixel change.
Flaky and Quarantined screenshots need no decision either. Flaky snapshots explains them.
3. Understand the comparison
The review workspace has five comparison modes: Side by Side, Overlay, Diff, Blink and 3-Up. Press 1 to 5 to switch between them. Use the one that answers the question fastest:
- Is the layout in the right place? Start with Side by Side.
- Did content, copy, or a state change intentionally? Diff highlights exactly which pixels changed.
- Did something move by a few pixels? Blink or Overlay makes small shifts visible.
- Is the difference only caused by a dynamic value or test instability?
- Is something missing, clipped, or unexpectedly restyled?
Check the relevant viewport and browser when the project captures more than one. Comparison modes and keyboard shortcuts describes each mode and every key.
| Key | Action |
|---|---|
j / k | Next / previous screenshot |
1 to 5 | Switch comparison mode |
a | Approve |
x | Reject |
u | Change the decision |
Enter | Finish review |
? | Show all shortcuts |
4. Make a decision
Choose Approve when the change is expected. Choose Reject when the change should not ship; add a comment so the next person knows what needs fixing.
After entering an optional rejection comment, select Confirm rejection to submit it or Cancel to keep the current decision. Ctrl + Enter (⌘ + Enter on a Mac) also confirms the rejection, and Esc cancels it. The confirmation button is disabled while the request is saving.
Approval does not update the baseline immediately. Decisions remain editable until the review is finished.
5. Finish the review
When every New and Changed screenshot has a decision, the footer shows Finish review. This also works when the build has only removals. Approve all includes pending removals, and Reject removals rejects pending removals with an optional shared comment. In advisory mode, removals remain optional and rejected removals keep their baselines without rejecting the build. In blocking mode, decide every removal before finishing. The project can ask for more before the button appears:
- Removed screenshots need a decision too when the project’s removal gating mode is Blocking.
- Degraded performance results need a decision when performance gating is blocking. See Findings without a pixel change.
Once it appears, the button can still stop you:
- The approval policy must be met when you approve anything. Until it is, Finish review is disabled and the review page shows a Review policy not met banner that lists who else has to approve. Approvals by an AI agent don’t count toward it.
- When accessibility gating is blocking, finishing fails until every accessibility Violations result has a decision in the Accessibility tab. Blocking console gating can make finishing fail with no way to decide; see Performance and console.
While Approve all or Finish review saves, the dialog shows a saving indicator and disables its buttons. Wait for it to complete. If the request fails, the dialog stays open and shows the error so you can retry.
pixmoat then publishes approved screenshots as the new baseline and reports the final result back to CI. Review complete lists what finishing changes.
If the build is rejected, fix the implementation and run the tests again. Do not approve a difference only to make the pipeline green.
Common decisions
| What you see | What to do |
|---|---|
| A deliberate redesign or copy change | Approve it after checking the affected viewports. |
| A button, section, or image moved unexpectedly | Reject it and fix the implementation. |
| A timestamp, avatar, or other changing value | Stabilize or mask the test data, then rerun. See Flaky snapshots. |
| A first-time screenshot with no baseline | Approve only after confirming the page is correct. |
| A screenshot that should no longer exist | Approve the removal only when deleting it was intentional. Approving it retires the baseline. |
| A screenshot whose size changed | Approve only if the new size is intended. See Size changes. |
Missing screenshots and removals
A screenshot can be missing from a build for two different reasons, and pixmoat shows them differently:
- The upload failed. When any upload fails, the client marks the whole build Failed instead of capture complete. A failed build can’t be reviewed and adds no Removed entries. Fix the upload problem and run the suite again.
- The test didn’t capture it. The build is complete, so pixmoat adds a Removed entry for every snapshot with a baseline that the build didn’t capture. That is correct when you deleted a test on purpose, and wrong when a test failed early or only part of the suite ran.
Before you approve a Removed screenshot, check that the test or page was removed on purpose. Approving it retires the baseline when you finish. To keep the baseline, reject the removal, restore the test and run the full suite again. Completeness and removals lists the accidental causes and what Approve all does with removals.
Size changes
When a screenshot’s width or height differs from its baseline, it shows as Changed with every pixel counted as different. There’s no separate label. The Diff mode shows both images on one canvas so you can see the difference in size.
Common causes are a page that grew or shrank with fullPage: true, a changed viewport, or a different pixel ratio. If the new size is intended, approve it: the new image replaces the baseline. If it isn’t, reject it and fix the page or the capture settings.
A snapshot that has no baseline at all is New, not a size change. On a feature branch, pixmoat first looks for a baseline on the default branch; see Baselines and branches.
Findings without a pixel change
A screenshot can match its baseline within tolerance and still have a performance, accessibility or console finding. By default these are advisory: they show in the screenshot’s tabs and need no decision. Console findings don’t show in the review page yet.
When the project sets their gating to blocking in Settings, a finding can need its own Approve or Reject in its tab before the review can finish, and rejecting one makes the build Rejected. While they wait for a decision, these findings don’t change the commit status or the CI gate verdict. Performance and console and Accessibility checks explain the details, including a few limits of blocking mode.
Superseded builds
When a newer build on the same branch finishes uploading, every older build on that branch that’s still Uploaded or In Review becomes Superseded. Its review page shows Superseded by a newer commit, and its decisions can’t be changed. Review the newer build instead. Decisions you made in the superseded build aren’t carried over.
Only the newest build on a branch can be reviewed, even before the older one is marked Superseded. Superseding a build doesn’t update the commit status of its commit.
A project admin can also close a build nobody needs to review. On the project’s builds page, under Review queue by branch, select Dismiss, then Remove. The build becomes Superseded and its baselines don’t change.
pixmoat doesn’t mark branches as stale. A branch keeps its own baselines until a build on it is approved again, and snapshots it never changed keep comparing with the default branch. If the default branch changed a snapshot after you approved it on your branch, merge promotion skips that snapshot; see Merge promotion.
Reopening a review
There’s no Reopen button. To change a decision after the review is complete, open the build, select Change on a screenshot and decide again. This starts a new review of the same build, which shows In Review until you finish again. It works only on the newest build of the branch.
While the review is reopened:
- The baselines written by the first finish stay as they are.
- The commit status stays as it was.
When you finish again, pixmoat writes the approved screenshots as baselines once more, updates the commit status, and the build shows Approved or Rejected. A screenshot you approved the first time and reject now keeps the baseline the first finish wrote. To undo that baseline, fix the page and approve a corrected screenshot in a new build.
Running CI again for the same commit also reopens the build: pixmoat deletes its screenshots and decisions and collects new ones. Baselines from an earlier finish stay.
Baseline history
To see how a snapshot’s baseline changed over time, select the screenshot and open More actions → History. Old versions keep their record after their image is removed by retention, and show a Pruned tile instead. Baselines and branches explains what’s kept and for how long.
When a diff looks suspicious
Check the current capture at the same viewport and browser as the baseline. If the change appears inconsistent between runs, look for animations, dynamic data, fonts, or network-dependent content before approving it. Flaky snapshots covers masking and capture-stability options.
Target changes during review
Finishing an approval rechecks target baseline images, versions, and comparison settings in the transaction that writes the review result. If those inputs changed, a blocking-mode branch review returns capture_ineligible with HTTP 409. Integration captures also require current provider verification and an accepted target capture for the exact target commit. A failed finish keeps the session open and preserves your staged decisions. Start a new capture against the current target before approving it.
Concurrent finish requests reuse the persisted terminal result. A retry or changed decision during finish cannot publish the earlier review inputs. GitLab verification happens before the database transaction; enforcing current source and target code at the moment of merge still requires provider merge rules. See Integration capture identity.
After approval, configured Git commit statuses update through a durable queue. If target changes make the capture stale, the queue publishes a non-passing result and preserves the historical approval. A provider outage delays delivery. See Commit status.