Screenshot Any Webpage in CI/CD with Zero Config
GitHub Actions examples using @openkova/cli — no API key, no SaaS account.
chromium-browser + @openkova/cli in your CI runner, then call kova screenshot <url>. That's it. The PNG is a plain file — upload it as an artifact, diff it, email it, or commit it. No SaaS account. MIT-licensed.Why screenshot in CI?
Screenshots in CI are useful for several things beyond visual regression:
- Deploy previews — capture the deployed preview URL on every PR and attach it as a build artifact so reviewers can see the rendered result without opening a browser
- OG image generation — render HTML templates to PNGs during build, output them as static assets, and avoid runtime image generation entirely
- PDF invoices and reports — convert HTML templates to PDFs as a CI/CD artifact, ready for download or S3 upload
- Visual regression — compare screenshots against stored baselines to catch unintended layout changes
- Documentation screenshots — keep screenshots in docs up to date by capturing them automatically on each release
Prerequisites in any CI environment
@openkova/cli needs a Chrome or Chromium binary. In most CI environments you install it with the system package manager:
# Ubuntu / Debian (GitHub Actions ubuntu-latest, GitLab runners)
sudo apt-get update && sudo apt-get install -y chromium-browser
# Alpine (lightweight Docker-based CI)
apk add --no-cache chromium
# macOS (GitHub Actions macos-latest)
brew install --cask google-chromeSet CHROMIUM_PATH if the binary is not on $PATH:
export CHROMIUM_PATH=/usr/bin/chromium-browserExample 1: screenshot a deploy preview URL
Capture the preview URL generated by your deployment step and upload it as an artifact so PR reviewers see the rendered output:
# .github/workflows/preview-screenshot.yml
name: Deploy Preview Screenshot
on: [pull_request]
jobs:
screenshot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Chromium
run: sudo apt-get update && sudo apt-get install -y chromium-browser
- name: Install kova
run: npm install -g @openkova/cli
- name: Deploy to preview environment
id: deploy
run: |
# Replace with your actual deploy command
PREVIEW_URL=$(npx vercel --token ${{ secrets.VERCEL_TOKEN }} --yes 2>&1 | tail -1)
echo "url=$PREVIEW_URL" >> $GITHUB_OUTPUT
- name: Screenshot preview
run: |
kova screenshot "${{ steps.deploy.outputs.url }}" \
--full-page --output preview.png
env:
CHROMIUM_PATH: /usr/bin/chromium-browser
- name: Upload screenshot
uses: actions/upload-artifact@v4
with:
name: deploy-preview
path: preview.pngExample 2: screenshot a locally running app
Start your app as a background process in the same CI job, wait for it to be ready, then capture it. This works for any framework — Next.js, Vite, Django, Rails, etc.:
# .github/workflows/app-screenshot.yml
name: App Screenshot
on: [pull_request]
jobs:
screenshot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Install Chromium and kova
run: |
sudo apt-get update && sudo apt-get install -y chromium-browser
npm install -g @openkova/cli
- name: Build app
run: npm run build
- name: Start app (background)
run: npm run start &
- name: Wait for app to be ready
run: npx wait-on http://localhost:3000 --timeout 30000
- name: Screenshot pages
run: |
mkdir -p screenshots
kova screenshot http://localhost:3000 --full-page --output screenshots/home.png
kova screenshot http://localhost:3000/about --full-page --output screenshots/about.png
kova screenshot http://localhost:3000/pricing --full-page --output screenshots/pricing.png
# Capture mobile viewport
kova screenshot http://localhost:3000 --viewport mobile --full-page --output screenshots/home-mobile.png
env:
CHROMIUM_PATH: /usr/bin/chromium-browser
- name: Upload screenshots
uses: actions/upload-artifact@v4
with:
name: page-screenshots
path: screenshots/Example 3: generate OG images during build
Generate all Open Graph images from HTML templates at build time instead of at request time. This avoids serverless cold starts, external API calls, and usage caps:
# .github/workflows/generate-og.yml
name: Generate OG Images
on:
push:
branches: [main]
paths: ['content/**', 'templates/**']
jobs:
og-images:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Chromium and kova
run: |
sudo apt-get update && sudo apt-get install -y chromium-browser
npm install -g @openkova/cli
- name: Generate OG images
run: |
mkdir -p public/og
for post in content/posts/*.md; do
title=$(grep '^title:' "$post" | sed 's/title: //')
slug=$(basename "$post" .md)
# Inject title into template and pipe to kova
sed "s/{{TITLE}}/$title/" templates/og.html | \
kova snippet --format png > "public/og/$slug.png"
done
env:
CHROMIUM_PATH: /usr/bin/chromium-browser
- name: Commit OG images
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add public/og/
git diff --staged --quiet || git commit -m "chore: regenerate OG images"
git pushExample 4: PDF invoice generation
Convert an HTML invoice template to PDF as a CI artifact, then upload it to S3 or attach it to a release:
- name: Generate invoice PDF
run: |
kova screenshot ./templates/invoice.html \
--format pdf \
--output invoice-$(date +%Y%m%d).pdf
env:
CHROMIUM_PATH: /usr/bin/chromium-browser
- name: Upload to S3
run: |
aws s3 cp invoice-*.pdf s3://my-bucket/invoices/GitLab CI
The same pattern works in GitLab CI. Use a node:20 image and install Chromium in the before_script:
# .gitlab-ci.yml
screenshot:
image: node:20
before_script:
- apt-get update && apt-get install -y chromium-browser
- npm install -g @openkova/cli
script:
- kova screenshot https://example.com --full-page --output screenshot.png
artifacts:
paths:
- screenshot.png
expire_in: 7 days
variables:
CHROMIUM_PATH: /usr/bin/chromium-browserKey flags reference
| Flag | Values | What it does |
|---|---|---|
--format | png jpeg webp pdf | Output format (default: png) |
--viewport | mobile desktop wide | Viewport preset |
--full-page | — | Capture full scrollable height |
--output | path/to/file.png | Output file path |
--depth | 1 2 | Crawl depth (for kova crawl) |
Frequently asked questions
How do I take a screenshot in GitHub Actions?
Install chromium-browser with apt-get, install @openkova/cli with npm, then call kova screenshot <url>. Set CHROMIUM_PATH=/usr/bin/chromium-browser. Use actions/upload-artifact to save the PNG.
Does @openkova/cli require an API key in CI?
No. It is MIT-licensed and runs using your CI environment's Chrome binary. No accounts, no API keys, no external service calls.
Can I screenshot a locally running app in CI?
Yes. Start your app in the background (npm run start &), wait for it to be ready (npx wait-on http://localhost:3000), then call kova screenshot http://localhost:3000. Everything runs in the same runner.
Does this work in GitLab CI, CircleCI, or other systems?
Yes. @openkova/cli is a plain npm package. Install Chromium with your system package manager and call kova as any other CLI. The CHROMIUM_PATH env var lets you point it at any browser binary.
Compare screenshots between runs: Visual Regression Testing Without Percy — or add a screenshot tool to your AI client: Add a Screenshot Tool to Claude Desktop, Cursor, and Windsurf.