GitHub Actions runners can call any HTTP API, so a screenshot or PDF is one curl step: no Chrome to install, no Puppeteer cache, no 300 MB browser download on every run. Below are three complete workflows you can drop into .github/workflows/. The shell steps were run against the live API before publishing; only the GitHub-specific parts (secrets, gh release upload) are standard Actions features we could not run here.
Get a key with 100 free renders at /pricing (no signup). In your repository, open Settings → Secrets and variables → Actions → New repository secret, name it SHOTMINT_KEY and paste the key. Workflows read it as ${{ secrets.SHOTMINT_KEY }}, and GitHub masks it in logs.
Every step below uses curl --fail-with-body: if a page can't be rendered (dead URL, timeout, out of credits), the API returns a JSON error, curl prints it and exits non-zero, and the job fails instead of saving an error message as shot.png. Failed renders cost nothing.
A visual record of your pages every Monday (and on demand with the Run workflow button), saved as a downloadable artifact. Useful for spotting layout breakage, keeping a design history, or feeding a changelog. Save as .github/workflows/screenshots.yml and change SITE and the paths:
name: Site screenshots
on:
schedule:
- cron: '0 6 * * 1' # Mondays 06:00 UTC
workflow_dispatch:
jobs:
shoot:
runs-on: ubuntu-latest
steps:
- name: Capture desktop and mobile screenshots
env:
SHOTMINT_KEY: ${{ secrets.SHOTMINT_KEY }}
SITE: https://example.com
run: |
mkdir -p shots
for path in / /pricing /docs; do
name=$(echo "$path" | tr '/' '_')
curl -sS --fail-with-body --get "https://shotmint.creasework.com/v1/screenshot" \
-H "X-API-Key: $SHOTMINT_KEY" \
--data-urlencode "url=$SITE$path" \
-d full_page=true -d format=jpeg -o "shots/desktop$name.jpg"
curl -sS --fail-with-body --get "https://shotmint.creasework.com/v1/screenshot" \
-H "X-API-Key: $SHOTMINT_KEY" \
--data-urlencode "url=$SITE$path" \
-d width=390 -d height=844 -d mobile=true -d device_scale_factor=2 \
-o "shots/mobile$name.png"
done
- uses: actions/upload-artifact@v4
with:
name: screenshots
path: shots/
Each page gives a full-length desktop JPEG (1280px wide, up to 16,000px tall) and a 390×844 mobile PNG at 2× (780×1688 pixels), rendered with a mobile user agent and touch, so responsive breakpoints apply. Six renders a run is about 312 a year, well inside a single €5 pack of 2,000 credits.
Vercel and other hosts that report GitHub deployments send a deployment_status event when a preview is live. This workflow captures the preview URL and attaches the image to the run, so reviewers can see the page without opening it:
name: Preview screenshot
on: deployment_status
jobs:
shoot:
if: github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- name: Screenshot the preview deployment
env:
SHOTMINT_KEY: ${{ secrets.SHOTMINT_KEY }}
PREVIEW_URL: ${{ github.event.deployment_status.environment_url }}
run: |
curl -sS --fail-with-body --get "https://shotmint.creasework.com/v1/screenshot" \
-H "X-API-Key: $SHOTMINT_KEY" \
--data-urlencode "url=$PREVIEW_URL" \
-d full_page=true -d format=jpeg -d delay=1000 -o preview.jpg
echo "Captured $PREVIEW_URL" >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@v4
with:
name: preview-screenshot
path: preview.jpg
delay=1000 gives client-side apps a second to finish rendering after the page loads. If your previews sit behind Vercel's Deployment Protection, the screenshot will show a login page: enable "Protection Bypass for Automation" in Vercel and append its x-vercel-protection-bypass parameter to the URL (with --data-urlencode it is encoded for you). Pull requests from forks don't get your secrets, which is what you want here.
When you publish a release, render a page (docs, changelog, a status report) to an A4 PDF and attach it to the release assets:
name: Docs PDF on release
on:
release:
types: [published]
permissions:
contents: write
jobs:
pdf:
runs-on: ubuntu-latest
steps:
- name: Render the docs page to PDF
env:
SHOTMINT_KEY: ${{ secrets.SHOTMINT_KEY }}
DOCS_URL: https://example.com/docs
run: |
curl -sS --fail-with-body "https://shotmint.creasework.com/v1/pdf" \
-H "X-API-Key: $SHOTMINT_KEY" \
-H "Content-Type: application/json" \
-d "{\"url\": \"$DOCS_URL\", \"format\": \"A4\", \"margin\": \"15mm\"}" \
-o docs.pdf
- name: Attach it to the release
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "${{ github.event.release.tag_name }}" docs.pdf --repo "${{ github.repository }}"
permissions: contents: write lets the built-in token upload release assets; gh is preinstalled on GitHub-hosted runners. Other PDF options: "landscape": true, "format": "Letter", "print_background": false, or "html" instead of "url" to render HTML your build produced (for example jq -Rs '{html: .}' report.html as the body).
| Approach | Good for |
|---|---|
| Puppeteer / Playwright in the job Free, but each run installs a browser (~1 min) and you manage fonts, sandbox flags and timeouts | Pages that need a login or clicks first, or tests that already run a browser. |
| Screenshot API step 1 credit per render, 100 free, then €5 for 2,000 (never expire) | Public pages and previews, PDFs from URLs or HTML, lightweight repos without a Node toolchain. |
If you already run Playwright tests, its own screenshot API is the natural fit. For many URLs at once, see bulk website screenshots; for no-code automations, n8n, Make and Zapier. Every parameter is in the API reference.
No signup, no card. Get a key in one click, then buy credits only if you need more (from €5 for 2,000, never expire).
Get a free API key Full API reference