Screenshots & PDFs in GitHub Actions

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.

Setup: store the key as a secret

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.

1. Weekly screenshots of your site, desktop and mobile

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.

2. Screenshot every preview deployment

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.

3. A PDF of your docs on every release

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).

Why an API instead of Puppeteer in the workflow

ApproachGood 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.

Try it with 100 free renders

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