Back to blog
· Apr 22, 2026· 2 min read
TutorialsCI/CDAutomation
Visual checks for every pull request with GitHub Actions
Capture your preview deployment on each PR and post the screenshots as a comment, so reviewers see the change without clicking through.
Ruby Le
Project Manager
Code review is good at catching logic bugs and bad at catching "the button is now white on white". A screenshot in the PR fixes that. This workflow captures a few pages of your preview deployment and comments the images on the pull request.
Prerequisites
- A preview URL per PR (Vercel, Netlify, Cloudflare Pages and most platforms provide one).
SNAPOPA_API_KEYstored as a repository secret.
The workflow
name: Visual preview
on:
pull_request:
jobs:
screenshots:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Capture pages
id: capture
env:
SNAPOPA_API_KEY: ${{ secrets.SNAPOPA_API_KEY }}
PREVIEW_URL: https://pr-${{ github.event.number }}.preview.example.com
run: |
body="### Visual preview"$'\n'
for path in / /pricing /docs; do
url=$(curl -s -X POST https://api.snapopa.com/capture \
-H "Authorization: Bearer $SNAPOPA_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"url\":\"$PREVIEW_URL$path\",\"format\":\"webp\",\"isFullPage\":true}" \
| jq -r '.data.fileUrl')
body+=$'\n'"**$path**"$'\n'""$'\n'
done
echo "body<<EOF" >> "$GITHUB_OUTPUT"
echo "$body" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
- name: Comment on PR
uses: marocchino/sticky-pull-request-comment@v2
with:
message: ${{ steps.capture.outputs.body }}The sticky comment action updates the same comment on each push instead of adding a new one.
Making it robust
- Wait for the deploy. Trigger on your platform's deployment-status event, or add a step that polls the preview URL until it returns 200.
- Mobile too. Add a second loop with
"viewport":{"width":390,"height":844}. - Keep the images. Capture files expire with
cdnTtl. For long-lived PRs, raisecdnTtlor use permalinks.