Using ShotSweep in CI
A typical pull-request workflow:
Pull Request
β
Build application
β
Start preview server
β
ShotSweep capture
β
ShotSweep diff
β
Visual changes detected?
β
PR feedbackCapture
- name: Capture screenshots
run: |
npx shotsweep capture \
--urls paths.json \
--mode sections \
--jsonCompare against the previous run
- name: Compare screenshots
run: |
npx shotsweep diff \
previous/manifest.json \
screenshots/manifest.json \
--summary \
--text ./reports/visual-summary.txt \
--jsonThe JSON output is useful for machines and CI tooling, while the text summary is useful as a human-readable build artifact.
Diff policy
ShotSweepβs default CI policy is:
| Result | Fails CI? |
|---|---|
changed | Yes |
size-changed | Yes |
error | Yes |
unchanged | No |
added | No |
removed | No |
Therefore:
- A genuine visual change fails the step.
- A screenshot resize fails the step.
- A page whose screenshots couldnβt be compared fails the step.
- An intentionally added page does not fail the step.
- An intentionally removed page does not fail the step.
Added and removed pages are still included in the diff report.
Threshold vs regression policy
These are two separate concepts.
Threshold controls sensitivity.
shotsweep diff before/manifest.json after/manifest.json --threshold strictRegression policy controls whether the resulting status fails the command.
For example, a page can be classified as changed because it exceeded the threshold. Since
changed is a regression, the command exits with 1.
See Diffing Two Runs for the complete status and threshold reference.
Config-driven CI
For projects that run the same visual comparison repeatedly, put the settings in
shotsweep.config.json.
{
"viewport": ["1440x900", "390x844"],
"diff": {
"out": "./diff",
"threshold": "default",
"summary": true,
"text": "./reports/visual-summary.txt"
}
}Then CI can stay short:
- name: Compare screenshots
run: |
npx shotsweep diff \
previous/manifest.json \
screenshots/manifest.jsonExplicit CLI flags override the config file, so CI can still tighten or loosen the comparison when needed.
Exit codes
Both commands are designed to gate a pipeline:
capturesets a non-zero exit code if any page failed to capture.diffsets a non-zero exit code whenchanged,size-changedorerrorresults are present.addedandremovedresults do not fail the build by default.
This allows CI to use the process exit code as the gate while using JSON, text, and the diff report as artifacts or inputs for further automation.
Reports and artifacts
A useful CI setup keeps three forms of output:
- Exit code β determines whether the step passes.
- JSON report β machine-readable data for scripts, bots, and AI tooling.
- Text summary β human-readable output for logs and build artifacts.
The diff directory can also contain the visual evidence:
diff/
βββ diff-report.json
βββ changed-page/
β βββ old.png
β βββ new.png
β βββ diff.png
βββ ...Upload the diff directory and text summary as CI artifacts when a build fails.
Visual regression protection
ShotSweep can be used to protect the documentation site itself.
For this repository, the intended flow is:
Pull request β Build docs site β Deploy preview β Capture preview β Compare against baseline β Changed or resized? β Fail CI β Merge blocked
The default ShotSweep regression policy treats changed and size-changed
results as failures. Added and removed pages are reported but do not fail the
workflow.
This makes visual comparison suitable for protected main branches: a pull
request can change documentation normally, while unintended visual changes
are caught before the pull request is merged.
Caching the browser
Playwright downloads a Chromium build on install. Cache it between CI runs to avoid re-downloading it every time:
| Platform | Cache path |
|---|---|
| Linux | ~/.cache/ms-playwright |
| macOS | ~/Library/Caches/ms-playwright |
| Windows | %USERPROFILE%\AppData\Local\ms-playwright |
Windows runners are noticeably slower than Linux ones at installs and browser startup, so caching
helps most there. actions/setup-node with cache: npm also speeds up npm ci.
Keep baselines comparable
Capture the baseline and the current run with the same ShotSweep version and the same runner
image. diff warns about environment drift
when they differ, and renderer differences can look like page changes. After upgrading ShotSweep,
re-capture the baseline (see Upgrading to 1.3).
Donβt send tokens to third parties
In CI you often pass --bearer $TOKEN or --header. These go only to the site being captured and
its subdomains, never to the fonts, analytics or CDN hosts the page loads. See
Where credentials are sent.